potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vm.c
Go to the documentation of this file.
1 
72 #include <stdio.h>
73 #include <stdarg.h>
74 #include <stdlib.h>
75 #include <math.h>
76 #include "potion.h"
77 #include "internal.h"
78 #include "opcodes.h"
79 #include "asm.h"
80 #include "khash.h"
81 #include "table.h"
82 
83 #if defined(POTION_JIT_TARGET) && defined(JIT_DEBUG)
84 # if defined(HAVE_LIBDISASM)
85 # include <libdis.h>
86 # else
87 # if defined(HAVE_LIBUDIS86)
88 # include <udis86.h>
89 # endif
90 // libdistorm64 has no usable headers yet
91 # endif
92 #endif
93 
94 //#define DEBUG_PROTO_DEBUG_LOOP
95 #define DEBUG_IN_C
96 #include <dlfcn.h>
97 #ifdef DEBUG_IN_C
98 enum {
99  DBG_STEP = 0,
104 };
105 static PN (*pn_readline)(Potion *, PN, PN, PN);
106 #else
107 #include "ast.h"
108 #endif
109 
110 #if DEBUG
111 extern const struct {
112  const char *name;
113  const u8 args;
114 } potion_ops[];
115 
116 #define STRINGIFY(_obj) ({PN str=potion_send(_obj,PN_string);str?PN_STR_PTR(str):"";})
117 #endif
118 
119 #ifdef POTION_JIT_TARGET
120 #if (POTION_JIT_TARGET == POTION_X86)
122 #elif (POTION_JIT_TARGET == POTION_PPC)
123 extern PNTarget potion_target_ppc;
124 #elif (POTION_JIT_TARGET == POTION_ARM)
125 extern PNTarget potion_target_arm;
126 #endif
127 #endif
128 
130 #ifdef POTION_JIT_TARGET
131 #if (POTION_JIT_TARGET == POTION_X86)
133 #elif (POTION_JIT_TARGET == POTION_PPC)
134  P->target = potion_target_ppc;
135 #elif (POTION_JIT_TARGET == POTION_ARM)
136  P->target = potion_target_arm;
137 #endif
138 #endif
139 }
140 
159 PN potion_vm_proto(Potion *P, PN cl, PN self, ...) {
160  PN ary = PN_NIL;
161  vPN(Proto) f = (struct PNProto *)PN_CLOSURE(cl)->data[0];
162  if (PN_IS_TUPLE(f->sig)) {
163  PN_SIZE i;
164  int arity = PN_CLOSURE(cl)->arity;
165  int minargs = PN_CLOSURE(cl)->minargs;
166  int numargs = 0;
167  va_list args;
168  ary = PN_TUP0();
169  va_start(args, self);
170  if (self < 10) {
171  numargs = self;
172  self = 0;
173  }
174  for (i=0; i < arity; i++) {
175  PN s = potion_sig_at(P, f->sig, i);
176  if (i < minargs || PN_TUPLE_LEN(s) < 2) { //mandatory or no type
177  ary = PN_PUSH(ary, va_arg(args, PN));
178  } else { //vararg call heuristic: check type of stack var, replace with default
179  PN arg = va_arg(args, PN);
180  char type = (char)(PN_TUPLE_LEN(s) > 2
182  : PN_TUPLE_LEN(s) > 1
183  ? PN_INT(PN_TUPLE_AT(s,1)) : 0);
184  if ((numargs && (i >= numargs)) //numargs provided via self
185  || PN_IS_FFIPTR(arg)
186  || (type && (potion_type_char(PN_TYPE(arg)) != type))) { //replace with default
187  // default value or 0
188  ary = PN_PUSH(ary, PN_TUPLE_LEN(s) == 3 ? PN_TUPLE_AT(s,2) : potion_type_default(type));
189  } else {
190  ary = PN_PUSH(ary, arg);
191  }
192  }
193  }
194  va_end(args);
195  }
196  return potion_vm(P, (PN)f, self, ary,
197  PN_CLOSURE(cl)->extra - 1, &PN_CLOSURE(cl)->data[1]);
198 }
199 
203 PN potion_vm_class(Potion *P, PN cl, PN self) {
204  if (PN_TYPE(cl) == PN_TCLOSURE) {
205  vPN(Proto) proto = PN_PROTO(PN_CLOSURE(cl)->data[0]);
206  PN ivars = potion_tuple_with_size(P, PN_TUPLE_LEN(proto->paths));
207  PN_TUPLE_EACH(proto->paths, i, v, {
208  PN_TUPLE_AT(ivars, i) = PN_TUPLE_AT(proto->values, PN_INT(v));
209  });
210  return potion_class(P, cl, self, ivars);
211  }
212 
213  return potion_class(P, PN_NIL, self, cl);
214 }
215 
216 #define STACK_MAX 4096
217 #define JUMPS_MAX 1024
218 
219 #define CASE_OP(name, args) case OP_##name: target->op[OP_##name]args; break;
220 
221 PN_F potion_jit_proto(Potion *P, PN proto) {
222  long regs = 0, lregs = 0, need = 0, rsp = 0, argx = 0, protoargs = 4;
223  PN_SIZE pos;
224  PNJumps jmps[JUMPS_MAX]; size_t offs[JUMPS_MAX]; int jmpc = 0, jmpi = 0;
225  vPN(Proto) f = (struct PNProto *)proto;
226  long upc = PN_TUPLE_LEN(f->upvals);
227  PNAsm * volatile asmb = potion_asm_new(P);
228  u8 *fn;
229  PNTarget *target = &P->target;
230  target->setup(P, f, &asmb);
231  DBG_t("-- run-time --\n");
232 
233  // calculate needed stackspace. nested protos may need more.
234  if (PN_TUPLE_LEN(f->protos) > 0) {
235  PN_SIZE j;
236  vPN(Tuple) tp = (vPN(Tuple)) potion_fwd(f->protos);
237  DBG_vt("; %d subprotos\n", tp->len);
238  for (j=0; j < tp->len; j++) {
239  PN proto2 = (PN)tp->set[j];
240  vPN(Proto) f2 = (struct PNProto *)proto2;
241  long p2args;
242  f2->arity = potion_sig_arity(P, f2->sig);
243  p2args = 3 + f2->arity;
244  if (f2->jit == NULL)
245  potion_jit_proto(P, proto2);
246  if (p2args > protoargs) {
247  DBG_vt("; extend stack from %ld to %ld\n", protoargs, p2args);
248  protoargs = p2args;
249  }
250  }
251  }
252 
253  regs = PN_INT(f->stack);
254  lregs = regs + PN_TUPLE_LEN(f->locals);
255  need = lregs + upc + 3;
256  /* single-byte indirect -(regn)%ebp addressing only works
257  up to 14 (64bit) or 29 (32bit) words */
258 #ifdef DEBUG
259  if (((need + 1) * sizeof(PN)) >= 0x7f)
260  DBG_c("Warning: %ld registers too many, used %ld, max %d.\n",
261  need-30/(PN_SIZE_T/4)+1, need, 30/(PN_SIZE_T/4)-1);
262 #endif
263  //assert((((need + 1) * sizeof(PN)) < 0x7f));
264  rsp = (need + protoargs) * sizeof(PN);
265 
266  target->stack(P, f, &asmb, rsp);
267  target->registers(P, f, &asmb, need);
268 
269  // Read locals
270  if (PN_IS_TUPLE(f->sig)) {
271  PN_SIZE i;
272  vPN(Tuple) t = (vPN(Tuple)) potion_fwd(f->sig);
273  for (i=0; i < t->len; i++) {
274  PN v = (PN)t->set[i];
275  // arg names, except string default
276  if (PN_IS_STR(v) && !(i>0 && PN_IS_INT(t->set[i-1]) && t->set[i-1] == PN_NUM(':'))) {
277  PN_SIZE num = PN_GET(f->locals, v);
278  if (num != PN_NONE)
279  target->local(P, f, &asmb, regs + num, argx);
280  argx++;
281  }
282  }
283  }
284  DBG_t("; %ld locals, %ld regs, %ld upc, sig=%s\n", argx, regs, upc, AS_STR(f->sig));
285  f->arity = argx;
286 
287  // if CL passed in with upvals, load them
288  if (upc > 0)
289  target->upvals(P, f, &asmb, lregs, need, upc);
290 
291  for (pos = 0; pos < PN_FLEX_SIZE(f->asmb) / sizeof(PN_OP); pos++) {
292  offs[pos] = asmb->len;
293  for (jmpi = 0; jmpi < jmpc; jmpi++) {
294  if (jmps[jmpi].to == pos) {
295  unsigned char *asmj = asmb->ptr + jmps[jmpi].from;
296  target->jmpedit(P, f, &asmb, asmj, asmb->len - (jmps[jmpi].from + 4));
297  }
298  }
299 
300  switch (PN_OP_AT(f->asmb, pos).code) {
301  CASE_OP(MOVE, (P, f, &asmb, pos)) // copy value between registers
302  CASE_OP(LOADK, (P, f, &asmb, pos, need)) // load a constant into a register
303  CASE_OP(LOADPN, (P, f, &asmb, pos)) // load a value into a register
304  CASE_OP(SELF, (P, f, &asmb, pos, need)) // prepare an object method for calling
305  // R[a+1] := R[b]; R[a] := R[b][RK[c]]
306  CASE_OP(GETLOCAL, (P, f, &asmb, pos, regs))// read a local into a register
307  CASE_OP(SETLOCAL, (P, f, &asmb, pos, regs))// write a register value into a local
308  CASE_OP(GETUPVAL, (P, f, &asmb, pos, lregs))// read an upvalue (upper scope)
309  CASE_OP(SETUPVAL, (P, f, &asmb, pos, lregs))// write to an upvalue
310  CASE_OP(GLOBAL, (P, f, &asmb, pos, need)) // returns a global (for get or set)
311  CASE_OP(NEWTUPLE, (P, f, &asmb, pos, need))// create tuple
312  CASE_OP(GETTUPLE, (P, f, &asmb, pos, need))// get tuple key (fast and unsafe)
313  CASE_OP(SETTUPLE, (P, f, &asmb, pos, need))// write register into tuple key
314  CASE_OP(GETTABLE, (P, f, &asmb, pos, need))// get table key
315  CASE_OP(SETTABLE, (P, f, &asmb, pos, need))// write register into a table entry
316  CASE_OP(NEWLICK, (P, f, &asmb, pos, need))// create lick. R[a] := {} (size = b,c)
317  CASE_OP(GETPATH, (P, f, &asmb, pos, need))// read obj field into register
318  CASE_OP(SETPATH, (P, f, &asmb, pos, need))// write into obj field
319  CASE_OP(ADD, (P, f, &asmb, pos, need)) // a = b + c
320  CASE_OP(SUB, (P, f, &asmb, pos, need)) // a = b - c
321  CASE_OP(MULT, (P, f, &asmb, pos, need))
322  CASE_OP(DIV, (P, f, &asmb, pos, need))
323  CASE_OP(REM, (P, f, &asmb, pos, need))
324  CASE_OP(POW, (P, f, &asmb, pos, need))
325  CASE_OP(NEQ, (P, f, &asmb, pos, need))
326  CASE_OP(EQ, (P, f, &asmb, pos, need)) // if ((RK[b] == RK[c]) ~= a) then PC++
327  CASE_OP(LT, (P, f, &asmb, pos)) // if ((RK[b] < RK[c]) ~= a) then PC++
328  CASE_OP(LTE, (P, f, &asmb, pos)) // if ((RK[b] <= RK[c]) ~= a) then PC++
329  CASE_OP(GT, (P, f, &asmb, pos))
330  CASE_OP(GTE, (P, f, &asmb, pos))
331  CASE_OP(BITN, (P, f, &asmb, pos, need))
332  CASE_OP(BITL, (P, f, &asmb, pos, need))
333  CASE_OP(BITR, (P, f, &asmb, pos, need))
334  CASE_OP(DEF, (P, f, &asmb, pos, need)) // define a method for an object
335  CASE_OP(BIND, (P, f, &asmb, pos, need)) // extend obj by set a binding
336  // http://piumarta.com/software/cola/colas-whitepaper.pdf
337  CASE_OP(MSG, (P, f, &asmb, pos, need)) // call a method of an object
338  CASE_OP(JMP, (P, f, &asmb, pos, jmps, offs, &jmpc)) // PC += sBx
339  CASE_OP(TEST, (P, f, &asmb, pos)) // if not (R[a] <=> C) then PC++
340  CASE_OP(NOT, (P, f, &asmb, pos)) // a = not b
341  CASE_OP(CMP, (P, f, &asmb, pos))
342  CASE_OP(TESTJMP, (P, f, &asmb, pos, jmps, offs, &jmpc))
343  CASE_OP(NOTJMP, (P, f, &asmb, pos, jmps, offs, &jmpc))
344  CASE_OP(NAMED, (P, f, &asmb, pos, need)) // assign named args before a CALL
345  CASE_OP(CALL, (P, f, &asmb, pos, need)) // call a function. R[a],...:= R[a]( R[a+1],...,R[a+b-1] )
346  CASE_OP(CALLSET, (P, f, &asmb, pos, need))//? set return register to write to
347  //CASE_OP(TAILCALL, (P, f, &asmb, pos, need))//? jump back to the function
348  CASE_OP(RETURN, (P, f, &asmb, pos)) // return R[a], ... ,R[a+b-2]
349  CASE_OP(PROTO, (P, f, &asmb, &pos, lregs, need, regs))// define function prototype
350  CASE_OP(CLASS, (P, f, &asmb, pos, need)) // find class for register value
351  //CASE_OP(DEBUG, (P, f, &asmb, pos, need)) // set lineno and filename
352  case OP_DEBUG: break; // skip ast debugging in jit
353  }
354  }
355 
356  target->finish(P, f, &asmb);
357 
358  fn = (u8*)PN_ALLOC_FUNC(asmb->len);
359 #if defined(JIT_DEBUG)
360  if (P->flags & DEBUG_JIT) {
361  #include "vm-dis.c"
362  }
363 #endif
364  PN_MEMCPY_N(fn, asmb->ptr, u8, asmb->len);
365 
366  return f->jit = (PN_F)fn;
367 }
368 
369 #define PN_VM_MATH2(name, oper) \
370  if (PN_IS_INT(reg[op.a]) && PN_IS_INT(reg[op.b])) \
371  reg[op.a] = PN_NUM(PN_INT(reg[op.a]) oper PN_INT(reg[op.b])); \
372  else { \
373  PN_CHECK_NUM(reg[op.a]); \
374  PN_CHECK_NUM(reg[op.b]); \
375  reg[op.a] = potion_obj_##name(P, reg[op.a], reg[op.b]); \
376  }
377 
378 #if (defined(__clang__) && ((__clang_major__ > 3) \
379  || (__clang_major__ == 3 && __clang_minor__ >= 4))) \
380  || (defined(__GNUC__) && __GNUC__ >= 5)
381 /* integer op overflow promotes to double, not bigint yet. */
382 # define PN_VM_MATH3(name, oper, ov) \
383  if (PN_IS_INT(reg[op.a]) && PN_IS_INT(reg[op.b])) { \
384  if (__builtin_##ov##_overflow(PN_INT(reg[op.a]), PN_INT(reg[op.b]), (long*)&val) \
385  || ((long)val > PN_INT(LONG_MAX)) \
386  || ((long)val < PN_INT(LONG_MIN))) \
387  reg[op.a] = potion_double(P, PN_DBL(reg[op.a]) oper PN_DBL(reg[op.b])); \
388  else \
389  reg[op.a] = PN_NUM((long)val); \
390  } \
391  else { \
392  PN_CHECK_NUM(reg[op.a]); \
393  PN_CHECK_NUM(reg[op.b]); \
394  reg[op.a] = potion_obj_##name(P, reg[op.a], reg[op.b]); \
395  }
396 #else
397 /* overflow detection only with gcc-5 or clang-3.6 builtins, or jit.
398  or super slow as in perl5 */
399 # define PN_VM_MATH3(name, oper, ov) PN_VM_MATH2(name, oper)
400 #endif
401 
402 // TODO: support str1 < str2, or list1 < list2? (i.e. call the cmp method)
403 #define PN_VM_NUMCMP(cmp) \
404  if (PN_IS_INT(reg[op.a]) && PN_IS_INT(reg[op.b])) \
405  reg[op.a] = PN_BOOL(reg[op.a] cmp reg[op.b]); \
406  else { \
407  PN_CHECK_NUM(reg[op.a]); \
408  PN_CHECK_NUM(reg[op.b]); \
409  reg[op.a] = PN_BOOL(PN_DBL(reg[op.a]) cmp PN_DBL(reg[op.b])); \
410  }
411 
412 #define PN_VM_CMP(cmp) reg[op.a] = cmp ? potion_vm_eq(P, reg[op.a], reg[op.b]) \
413  : potion_vm_neq(P, reg[op.a], reg[op.b]);
414 
415 /* we need that for the jit, too large to be inlined there */
416 PN potion_vm_eq(Potion *P, PN a, PN b) {
417  if (PN_IS_DBL(a) && PN_IS_DBL(b)) {
418  return PN_BOOL(PN_DBL(a) == PN_DBL(b));
419  } else if (PN_IS_PTR(a)) {
420  PN_QUICK_FWD(PN, a);
421  return PN_BOOL(a == potion_fwd(b));
422  } else {
423  return PN_BOOL(a == b);
424  }
425 }
426 
427 PN potion_vm_neq(Potion *P, PN a, PN b) {
428  if (PN_IS_DBL(a) && PN_IS_DBL(b)) {
429  return PN_BOOL(((struct PNDouble *)a)->value != ((struct PNDouble *)b)->value);
430  } else if (PN_IS_PTR(a)) {
431  PN_QUICK_FWD(PN, a);
432  return PN_BOOL(a != potion_fwd(b));
433  } else {
434  return PN_BOOL(a != b);
435  }
436 }
437 
438 static PN potion_sig_check(Potion *P, struct PNClosure *cl, int arity, int numargs) {
439  if (numargs > 0) { //allow fun() to return the closure
440  if (numargs < cl->minargs)
441  return potion_error
442  (P, (cl->minargs == arity
443  ? potion_str_format(P, "Not enough arguments to %s. Required %d, given %d",
444  AS_STR(cl), arity, numargs)
445  : potion_str_format(P, "Not enough arguments to %s. Required %d to %d, given %d",
446  AS_STR(cl), cl->minargs, arity, numargs)),
447  0, 0, 0);
448  if (numargs > arity)
449  return potion_error
450  (P, potion_str_format(P, "Too many arguments to %s. Allowed %d, given %d",
451  AS_STR(cl), arity, numargs), 0, 0, 0);
452  }
453  return PN_NIL;
454 }
455 
456 PN potion_debug(Potion *P, struct PNProto *f, PN self, PN_OP op, PN* reg, PN* stack) {
457  if (P->flags & EXEC_DEBUG) {
458  PN ast;
459  //PN *upvals;
460  //PN *locals;
461  //PN *current = stack;
462  //upvals = current;
463  //locals = upvals + f->upvalsize;
464 
465  if (PN_IS_TUPLE(f->debugs) && op.b >= 0 && op.b < PN_TUPLE_LEN(f->debugs))
466  ast = PN_TUPLE_AT(f->debugs, op.b);
467  else
468  ast = PN_NIL;
469 #ifndef DEBUG_IN_C
470  // get AST from debug op
471  DBG_t("\nEntering debug loop\n");
472  DBG_vt("calling debug loop(src, proto)\n");
473  PN flags = (PN)P->flags; P->flags = EXEC_VM; //turn off tracing,debugging,...
474 # ifdef DEBUG_PROTO_DEBUG_LOOP // This is the planned way to go.
475  // debug.pn loaded, debug object in upvals, call the init and loop method on it
476  PN debug = potion_message(P, self, PN_STR("debug")); // find debug object =>0
477  if (!debug) return PN_NUM(0);
478  PN loopmeth = potion_message(P, debug, PN_STR("loop"));
479  PN code = potion_vm_proto(P, (PN)PN_CLOSURE_F(loopmeth), debug, ast, (PN)f);
480 # else
481  // avoid the GC-unsafe parser, and there's no other way yet to inject
482  // the current AST into the parser. (ast object?)
483  // - expr (msg ("debug"), msg ("loop" list (expr (src), ...))
484  PN code = (PN)PN_AST_(CODE,
485  PN_TUP(PN_AST_(EXPR, PN_PUSH(PN_TUP(PN_AST_(MSG, PN_STR("debug"))),
486  PN_AST2_(MSG, PN_STR("loop"),
487  PN_AST_(LIST, PN_PUSH(PN_TUP(PN_AST_(MSG, ast)), PN_AST_(MSG, (PN)f))))))));
488  code = potion_send(code, PN_compile, (PN)f, PN_NIL);
489  //locals = locals;
490  code = potion_vm(P, code, P->lobby, PN_NIL, f->upvalsize, upvals);
491 # endif // DEBUG_PROTO_DEBUG_LOOP
492  //locals = locals;
493  P->flags = flags;
494  if (code >= PN_NUM(5)) { // :q, :exit
495  P->flags &= ~EXEC_DEBUG);
496  if (code == PN_NUM(6)) // :exit
497  exit(0);
498  }
499 #else // DEBUG_IN_C This is a hack and will go away
500  int loop = 1;
501  //locals = locals;
502  // TODO: check for breakpoints
503  vPN(Source) t = (struct PNSource*)ast;
504  if (t) {
505  if (t->line) {
506  PN fn = PN_TUPLE_AT(pn_filenames, t->loc.fileno);
507  if (fn) printf("(%s:%d):\t%s\n", PN_STR_PTR(fn), t->loc.lineno, PN_STR_PTR(t->line));
508  else printf("(:%d):\t%s\n", t->loc.lineno, PN_STR_PTR(t->line));
509  }
510  while (loop) {
511  PN str = pn_readline(P, self, self, PN_STRN("> ", 2));
512  if (str && potion_cp_strlen_utf8(PN_STR_PTR(str)) > 1
513  && PN_STR_PTR(str)[0] == ':')
514  {
515  if (str == PN_STR(":c")) { break; }
516  else if (str == PN_STR(":q")) { P->flags -= EXEC_DEBUG; break; }
517  else if (str == PN_STR(":exit")) { exit(0); }
518  else if (str == PN_STR(":h")) {
519  printf("c readline debugger (no breakpoints and lexical env yet)\n"
520  ":q quit debugger and continue\n"
521  ":exit quit debugger and exit\n"
522  ":c continue\n"
523  ":b line set breakpoint (nyi)\n"
524  ":B line unset breakpoint (nyi)\n"
525  ":n step to next line (nyi)\n"
526  ":s step into function (nyi)\n"
527  "/r registers\n"
528  "/l locals\n" /* paths in debug */
529  "/u upvals\n"
530  "/v values\n"
531  "/p paths\n"
532  "expr eval expr");
533  }
534  else {
535  printf("sorry, no debugger commands yet\n");
536  }
537  }
538  else if (str && str != PN_STR("")) {
539  PN flags = (PN)P->flags; P->flags = (Potion_Flags)EXEC_VM;
540 #if 0
541  vPN(Closure) cl;
542  vPN(Tuple) sig;
543  vPN(Tuple) regs;
544  int i;
545  PN_F debug_fn;
546  PN_SIZE pos;
547  PN oldsig = f->sig;
548 #endif
549  PN code = potion_parse(P, potion_send(str, PN_STR("bytes")), "-d");
550 
551  code = potion_send(code, PN_compile, (PN)f, PN_NIL);
552  printf("%s\n", AS_STR(potion_run(P, code, P->flags)));
553 #if 0
554  /* TODO cannot access the current upvals, regs, locals, values, paths yet */
555  sig = (struct PNTuple *) potion_tuple_with_size(P, 5);
556  PN_TUPLE_AT(sig, 0) = PN_STR("r"); //regs
557  PN_TUPLE_AT(sig, 1) = PN_STR("l"); //locals
558  PN_TUPLE_AT(sig, 2) = PN_STR("u"); //upvals
559  PN_TUPLE_AT(sig, 3) = PN_STR("v"); //values
560  PN_TUPLE_AT(sig, 4) = PN_STR("p"); //paths
561  cl = (struct PNClosure *)potion_closure_new(P, (PN_F)potion_vm_proto, (PN)sig,
562  PN_TUPLE_LEN(f->upvals) + 6);
563  cl->data[0] = (PN)f;
564  pos = 0;
565  PN_TUPLE_COUNT(f->upvals, i, {
566  pos++;
567  op = PN_OP_AT(f->asmb, pos);
568  if (op.code == OP_GETUPVAL) {
569  cl->data[i+1] = upvals[op.b];
570  } else if (op.code == OP_GETLOCAL) {
571  cl->data[i+1] = locals[op.b] = (PN)potion_ref(P, locals[op.b]);
572  } else {
573  fprintf(stderr, "** missing an upval to proto %p\n", (void *)f);
574  }
575  });
576  regs = (struct PNTuple *) potion_tuple_with_size(P, PN_INT(f->stack));
577  for (i=0; i < PN_INT(f->stack); i++) { regs->set[i] = reg[i]; }
578  debug_fn = PN_CLOSURE_F(cl);
579  printf("%s\n", AS_STR(debug_fn(P, (PN)cl, code /*, regs, f->locals,
580  f->upvals, f->values, f->paths */)));
581  f->sig = oldsig;
582 #endif
583  P->flags = flags;
584  }
585  else loop=0;
586  }
587  }
588 #endif // DEBUG_IN_C
589  }
590  return PN_NUM(0);
591 }
592 
594 PN potion_vm(Potion *P, PN proto, PN self, PN vargs, PN_SIZE upc, PN *upargs) {
595  vPN(Proto) f = (struct PNProto *)proto;
596 
597  // these variables persist as we jump around. TODO: static PN (auto-zeroed)
598  PN stack[STACK_MAX];
599  PN val = PN_NIL;
600 
601  // these variables change from proto to proto
602  // current = upvals | locals | self | reg
603  PN_SIZE pos = 0;
604  PN *args = NULL, *upvals, *locals, *reg;
605  PN *current = stack;
606 
607 #ifdef DEBUG_IN_C
608  if (P->flags & EXEC_DEBUG) {
609  pn_readline = (PN (*)(Potion *, PN, PN, PN))dlsym(RTLD_DEFAULT, "pn_readline");
610  if (!pn_readline) {
611 #ifndef SANDBOX
612  void *handle = dlopen(potion_find_file(P,"readline",0), RTLD_LAZY);
613  if (!handle) potion_fatal("readline library not loaded");
614  pn_readline = (PN (*)(Potion *, PN, PN, PN))dlsym(handle, "pn_readline");
615 #endif
616  if (!pn_readline) potion_fatal("pn_readline function not loaded");
617  }
618  DBG_t("\nEntering c debug mode");
619  printf("\nc debug (:h for help, <enter> for continue)\n");
620  }
621 #endif
622 
623  if (vargs != PN_NIL) args = PN_GET_TUPLE(vargs)->set;
624  memset((void*)stack, 0, STACK_MAX*sizeof(PN));
625  DBG_t("-- run-time --\n");
626 
627 reentry:
628  if (current - stack >= STACK_MAX) { // 4096
629  potion_fatal("Out of stack, all registers used up!");
630  }
631 
632  upvals = current;
633  locals = upvals + f->upvalsize;
634  reg = locals + f->localsize + 1;
635 
636  if (pos == 0) {
637  reg[-1] = reg[0] = self;
638  //if (f->localsize)
639  // memset((void*)locals, 0, sizeof(PN) * f->localsize);
640  if (upc > 0 && upargs != NULL) {
641  PN_SIZE i;
642  for (i = 0; i < upc; i++) {
643  upvals[i] = upargs[i];
644  }
645  }
646  if (args != NULL) {
647  long argx;
648  for (argx = 0; argx < potion_sig_arity(P, f->sig); argx++) {
649  PN s = potion_sig_name_at(P, f->sig, argx);
650  PN_SIZE num = PN_GET(f->locals, s);
651  if (num != PN_NONE)
652  locals[num] = args[argx];
653  }
654  }
655  }
656 
657  PN_SIZE len = PN_OP_LEN(f->asmb);
658  while (pos < len) {
659  PN_OP op = PN_OP_AT(f->asmb, pos);
660  DBG_t("[%2d] %-8s %d ", pos+1, potion_ops[op.code].name, op.a);
661 #ifdef DEBUG
662  if (P->flags & DEBUG_TRACE) {
663  if (potion_ops[op.code].args > 1)
664  fprintf(stderr, "%d", op.b);
665  if (op.code == OP_DEBUG) fprintf(stderr, "\n");
666  }
667 #endif
668 
669 // computed goto jmptable instead of switch does not check boundaries, ~3-11% faster
670 #ifdef CGOTO
671 #define L(op) L_##op
672 
673  static void *jmptbl[] = {
674  &&L(NONE), &&L(MOVE), &&L(LOADK), &&L(LOADPN), &&L(SELF), &&L(NEWTUPLE),
675  &&L(GETTUPLE), &&L(SETTUPLE), &&L(GETLOCAL), &&L(SETLOCAL), &&L(GETUPVAL),
676  &&L(SETUPVAL), &&L(GLOBAL), &&L(GETTABLE), &&L(SETTABLE), &&L(NEWLICK),
677  &&L(GETPATH), &&L(SETPATH), &&L(ADD), &&L(SUB), &&L(MULT), &&L(DIV), &&L(REM),
678  &&L(POW), &&L(NOT), &&L(CMP), &&L(EQ), &&L(NEQ), &&L(LT), &&L(LTE), &&L(GT),
679  &&L(GTE), &&L(BITN), &&L(BITL), &&L(BITR), &&L(DEF), &&L(BIND), &&L(MSG), &&L(JMP),
680  &&L(TEST), &&L(TESTJMP), &&L(NOTJMP), &&L(NAMED), &&L(CALL), &&L(CALLSET),
681  &&L(TAILCALL), &&L(RETURN), &&L(PROTO), &&L(CLASS), &&L_DEBUG
682  };
683 
684 #define SWITCH_START(op) goto *jmptbl[op.code];
685 #define CASE(op, block) L(op): { block; } goto L_end;
686 #define SWITCH_END L_end: ;
687 #else
688 #define SWITCH_START(op) switch (op.code) {
689 #define CASE(op, block) case OP_##op: block; break;
690 #define SWITCH_END }
691 #endif
692 
693  SWITCH_START(op)
694  CASE(MOVE, reg[op.a] = reg[op.b] )
695  CASE(LOADK, reg[op.a] = PN_TUPLE_AT(f->values, op.b) )
696  CASE(LOADPN, reg[op.a] = (PN)op.b )
697  CASE(SELF, reg[op.a] = reg[-1] )
698  CASE(GETLOCAL,
699  if (PN_IS_REF(locals[op.b])) {
700  DBG_vt("; deref locals %d\n", op.b);
701  reg[op.a] = PN_DEREF(locals[op.b]);
702  } else {
703  reg[op.a] = locals[op.b];
704  }
705  )
706  CASE(SETLOCAL,
707  if (PN_IS_REF(locals[op.b])) {
708  DBG_vt("; deref locals %d\n", op.b);
709  PN_DEREF(locals[op.b]) = reg[op.a];
710  PN_TOUCH(locals[op.b]);
711  } else
712  locals[op.b] = reg[op.a]
713  )
714  CASE(GETUPVAL, reg[op.a] = PN_DEREF(upvals[op.b]) )
715  CASE(SETUPVAL,
716  PN_DEREF(upvals[op.b]) = reg[op.a];
717  PN_TOUCH(upvals[op.b])
718  )
719  CASE(GLOBAL,
720  potion_define_global(P, reg[op.a], reg[op.b]);
721  reg[op.a] = reg[op.b])
722  CASE(NEWTUPLE,
723  reg[op.a] = PN_TUP0())
724  CASE(GETTUPLE, { /* fast unsafe version, not bound checked */
725  vPN(Tuple) tpl = (vPN(Tuple))potion_fwd(reg[op.a]);
726  DBG_CHECK_TUPLE(tpl);
727  long i = op.b & ASM_TPL_IMM ? PN_INT(reg[op.b - ASM_TPL_IMM]) : op.b;
728  reg[op.a] = PN_TUPLE_AT(tpl, i);
729  })
730  CASE(SETTUPLE,
731  reg[op.a] = PN_PUSH(reg[op.a], reg[op.b]))
732  CASE(GETTABLE,
733  reg[op.a] = potion_table_at(P, PN_NIL, reg[op.a], reg[op.b]))
734  CASE(SETTABLE,
735  potion_table_set(P, reg[op.a], reg[op.a + 1], reg[op.b]))
736  CASE(NEWLICK, {
737  PN attr = op.b > op.a ? reg[op.a + 1] : PN_NIL;
738  PN inner = op.b > op.a + 1 ? reg[op.b] : PN_NIL;
739  reg[op.a] = potion_lick(P, reg[op.a], attr, inner);
740  })
741  CASE(GETPATH,
742  reg[op.a] = potion_obj_get(P, PN_NIL, reg[op.a], reg[op.b]))
743  CASE(SETPATH,
744  potion_obj_set(P, PN_NIL, reg[op.a], reg[op.a + 1], reg[op.b]))
745  CASE(ADD, PN_VM_MATH3(add, +, saddl))
746  CASE(SUB, PN_VM_MATH3(sub, -, ssubl))
747  CASE(MULT,PN_VM_MATH3(mult, *, smull))
748  CASE(DIV, PN_VM_MATH2(div, /))
749  CASE(REM, PN_VM_MATH2(rem, %))
750  CASE(POW, reg[op.a] = PN_NUM((int)pow((double)PN_INT(reg[op.a]),
751  (double)PN_INT(reg[op.b]))))
752 #ifdef P2
753  CASE(NOT, reg[op.a] = PN_ZERO == reg[op.a] ? PN_TRUE : PN_BOOL(!PN_TEST(reg[op.a])))
754 #else
755  CASE(NOT, reg[op.a] = PN_BOOL(!PN_TEST(reg[op.a])))
756 #endif
757  CASE(CMP, reg[op.a] = PN_NUM(PN_INT(reg[op.b]) - PN_INT(reg[op.a])))
758  CASE(NEQ,
759  DBG_t("\t; %s!=%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
760  PN_VM_CMP(0))
761  CASE(EQ,
762  DBG_t("\t; %s==%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
763  PN_VM_CMP(1))
764  CASE(LT,
765  DBG_t("\t; %s<%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
766  PN_VM_NUMCMP(<))
767  CASE(LTE,
768  DBG_t("\t; %s<=%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
769  PN_VM_NUMCMP(<=))
770  CASE(GT,
771  DBG_t("\t; %s>%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
772  PN_VM_NUMCMP(>))
773  CASE(GTE,
774  DBG_t("\t; %s>=%s", STRINGIFY(reg[op.a]), STRINGIFY(reg[op.b]));
775  PN_VM_NUMCMP(>=))
776  CASE(BITN,
777  reg[op.a] = PN_IS_INT(reg[op.b]) ? PN_NUM(~PN_INT(reg[op.b])) : potion_obj_bitn(P, reg[op.b]))
778  CASE(BITL, PN_VM_MATH2(bitl, <<))
779  CASE(BITR, PN_VM_MATH2(bitr, >>))
780  CASE(DEF,
781  reg[op.a] = potion_def_method(P, PN_NIL, reg[op.a], reg[op.a + 1], reg[op.b]))
782  CASE(BIND,
783  reg[op.a] = potion_bind(P, reg[op.b], reg[op.a]))
784  CASE(MSG,
785  reg[op.a] = potion_message(P, reg[op.b], reg[op.a]))
786  CASE(JMP,
787  pos += op.a)
788  CASE(TEST,
789  reg[op.a] = PN_BOOL(PN_TEST(reg[op.a])))
790  CASE(TESTJMP,
791  if (PN_TEST(reg[op.a])) pos += op.b)
792  CASE(NOTJMP,
793  if (!PN_TEST(reg[op.a])) pos += op.b)
794  CASE(NAMED, {
795  int x = potion_sig_find(P, reg[op.a], reg[op.b - 1]);
796  if (x >= 0) reg[op.a + x + 2] = reg[op.b];
797  else potion_fatal("named parameter not found in signature");
798  DBG_t("\t; %s=%s at %d", STRINGIFY(reg[op.b-1]), STRINGIFY(reg[op.b]), x);
799  })
800  CASE(CALL, /* R[a]( R[a+1],...,R[a+b-1] ) */
801  switch (PN_TYPE(reg[op.a])) {
802  case PN_TVTABLE:
803  DBG_vt(" VTABLE\n");
804  reg[op.a + 1] = potion_object_new(P, PN_NIL, reg[op.a]);
805  reg[op.a] = ((struct PNVtable *)reg[op.a])->ctor;
806  case PN_TCLOSURE:
807  {
808  vPN(Closure) cl = PN_CLOSURE(reg[op.a]);
809  int i;
810  PN sig = cl->sig;
811  int numargs = op.b - op.a - 1;
812  if (cl->method != (PN_F)potion_vm_proto) { //call into a lib or jit or ffi
813  //DBG_vt(" ext");
814  if (PN_IS_TUPLE(sig)) {
815  int arity = cl->arity;
816  PN err = potion_sig_check(P, cl, arity, numargs);
817  if (err) return err;
818  for (i=numargs; i < arity; i++) { // fill in defaults
819  PN s = potion_sig_at(P, sig, i);
820  if (s) // default or zero: && !filled by NAMED (?)
821  reg[op.a + i + 2] = PN_TUPLE_LEN(s) == 3
822  ? PN_TUPLE_AT(s, 2)
824  op.b++;
825  }
826  }
827  reg[op.a] = potion_call(P, reg[op.a], op.b - op.a, reg + op.a + 1);
828  } else if (((reg - stack) + PN_INT(f->stack) + f->upvalsize + f->localsize + 8) >= STACK_MAX) {
829  DBG_vt(" >stack");
830  PN argt = potion_tuple_with_size(P, (op.b - op.a) - 1);
831  for (i = 2; i < op.b - op.a; i++)
832  PN_TUPLE_AT(argt, i - 2) = reg[op.a + i];
833  reg[op.a] = potion_vm(P, cl->data[0], reg[op.a + 1], argt,
834  cl->extra - 1, &cl->data[1]);
835  } else {
836  DBG_vt(" stack");
837  self = reg[op.a + 1];
838  args = &reg[op.a + 2];
839  if (PN_IS_TUPLE(sig)) {
840  int arity = cl->arity;
841  PN err = potion_sig_check(P, cl, arity, numargs);
842  if (err) return err;
843  for (i=numargs; i < arity; i++) { // fill in defaults. TODO compile-time
844  PN s = potion_sig_at(P, sig, i);
845  if (s) // default or zero: && !filled by NAMED (?)
846  reg[op.a + i + 2] = PN_TUPLE_LEN(s) == 3
847  ? PN_TUPLE_AT(s, 2)
849  f->stack = PN_NUM(PN_INT(f->stack)+1);
850  op.b++;
851  }
852  }
853  upc = cl->extra - 1;
854  upargs = &cl->data[1];
855  current = reg + PN_INT(f->stack) + 2;
856  current[-2] = (PN)f;
857  current[-1] = (PN)pos;
858 
859  f = PN_PROTO(cl->data[0]);
860  pos = 0;
861  DBG_t("\t; %s\n", STRINGIFY(reg[op.a]));
862  goto reentry;
863  }
864  }
865  break;
866 
867  default: {
868  reg[op.a + 1] = reg[op.a];
869  reg[op.a] = potion_obj_get_call(P, reg[op.a]);
870  if (PN_IS_CLOSURE(reg[op.a])) {
871  //DBG_vt(" def");
872  reg[op.a] = potion_call(P, reg[op.a], op.b - op.a, &reg[op.a + 1]);
873  }
874  DBG_t("\t; %s\n", STRINGIFY(reg[op.a]));
875  }
876  break;
877  })
878  CASE(CALLSET,
879  reg[op.a] = potion_obj_get_callset(P, reg[op.b]))
880  CASE(TAILCALL,
881  potion_fatal("OP_TAILCALL not implemented"))
882  CASE(NONE, ) // ignored
883  CASE(RETURN,
884  if (current != stack) {
885  val = reg[op.a];
886 
887  f = PN_PROTO(current[-2]);
888  pos = (PN_SIZE)current[-1];
889  op = PN_OP_AT(f->asmb, pos);
890 
891  reg = current - (PN_INT(f->stack) + 2);
892  current = reg - (f->localsize + f->upvalsize + 1);
893  reg[op.a] = val;
894  pos++;
895  DBG_t("\t; %s\n", STRINGIFY(val));
896  goto reentry;
897  } else {
898  reg[0] = reg[op.a];
899  DBG_t("\t; %s\n", STRINGIFY(reg[op.a]));
900  goto done;
901  }
902  )
903  CASE(PROTO, { /* define a method */
904  vPN(Closure) cl;
905  unsigned areg = op.a;
906  proto = PN_TUPLE_AT(f->protos, op.b);
908  PN_PROTO(proto)->sig, PN_TUPLE_LEN(PN_PROTO(proto)->upvals) + 1);
909  cl->data[0] = proto;
910  PN_TUPLE_COUNT(PN_PROTO(proto)->upvals, i, {
911  pos++;
912  op = PN_OP_AT(f->asmb, pos);
913  if (op.code == OP_GETUPVAL) {
914  cl->data[i+1] = upvals[op.b];
915  } else if (op.code == OP_GETLOCAL) {
916  cl->data[i+1] = locals[op.b] = (PN)potion_ref(P, locals[op.b]);
917  } else {
918  fprintf(stderr, "** missing an upval to proto %p\n", (void *)proto);
919  }
920  });
921  reg[areg] = (PN)cl;
922  })
923  CASE(CLASS, reg[op.a] = potion_vm_class(P, reg[op.b], reg[op.a]))
924 #ifdef CGOTO
925  L_DEBUG:
926 #else
927  case OP_DEBUG:
928 #endif
929  potion_debug(P, f, self, op, reg, stack);
930 
931  SWITCH_END
932 
933 #ifdef DEBUG
934  if (P->flags & DEBUG_TRACE) {
935  if (op.code == OP_JMP || op.code == OP_NOTJMP || op.code == OP_TESTJMP ||
936  op.code == OP_NAMED)
937  fprintf(stderr, "\n");
938  else
939  fprintf(stderr, "\t; %s\n", STRINGIFY(reg[op.a]));
940  }
941 #endif
942  pos++;
943  }
944 
945 done:
946  val = reg[0];
947  return val;
948 }
#define PN_CLOSURE_F(x)
Definition: potion.h:217
#define PN_TUPLE_AT(t, n)
Definition: potion.h:269
PN PN_compile
Definition: internal.c:14
void(* finish)(Potion *, struct PNProto *volatile, PNAsm *volatile *)
Definition: potion.h:595
#define PN_IS_STR(v)
Definition: potion.h:166
PN asmb
assembled instructions
Definition: potion.h:458
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
Definition: objmodel.c:17
PN upvals
variables in upper scopes
Definition: potion.h:452
PN potion_def_method(Potion *P, PN closure, PN self, PN key, PN method)
define a method for a class
Definition: objmodel.c:346
bytecode (switch or cgoto)
Definition: potion.h:606
#define DBG_vt(...)
Definition: potion.h:246
void potion_vm_init(Potion *P)
Definition: vm.c:129
PN name
Definition: potion.h:379
PN potion_class(Potion *P, PN cl, PN self, PN ivars)
create a user-class (ie type)
Definition: objmodel.c:252
void(* setup)(Potion *, struct PNProto *volatile, PNAsm *volatile *)
Definition: potion.h:588
record labels to be patched
Definition: asm.h:20
#define vPN(t)
Definition: potion.h:132
klib hash table library based on double hashing http://en.wikipedia.org/wiki/Double_hashing ...
PN_F potion_jit_proto(Potion *, PN)
a tuple is an array of PNs.
Definition: potion.h:468
PN potion_table_set(Potion *, PN, PN, PN)
helper function for potion_table_put:"put", accepts tuple or table
Definition: table.c:126
#define PN_TCLOSURE
Definition: potion.h:114
PN pn_filenames
Definition: internal.c:23
#define PN_CLOSURE(x)
Definition: potion.h:216
Potion_Flags flags
vm flags: execution model and debug flags
Definition: potion.h:650
PN potion_bind(Potion *P, PN rcv, PN msg)
find method for given receiver and message (method lookup)
Definition: objmodel.c:403
a closure is an anonymous function, without closed values,
Definition: potion.h:372
the central vtable, see io http://www.piumarta.com/pepsi/objmodel.pdf
Definition: table.h:24
PN potion_obj_set(Potion *P, PN cl, PN self, PN ivar, PN value)
implements OP_SETPATH
Definition: objmodel.c:329
#define STRINGIFY(_obj)
Definition: vm.c:116
void(* stack)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long)
Definition: potion.h:589
int potion_sig_find(Potion *, PN, PN)
static PN potion_type_default(char type)
zero values per type
Definition: potion.h:796
#define PN_VM_MATH3(name, oper, ov)
Definition: vm.c:399
PNTarget target
the jit
Definition: potion.h:646
#define PN_TUPLE_LEN(t)
Definition: potion.h:268
#define PN_IS_FFIPTR(p)
Definition: potion.h:172
#define AS_STR(x)
Definition: potion.h:240
PN potion_ref(Potion *P, PN data)
Definition: objmodel.c:467
Potion_Flags
Definition: potion.h:628
#define PN_PUSH(T, X)
Definition: potion.h:263
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
Definition: potion.h:561
Definition: opcodes.h:48
char potion_type_char(PNType type)
valid signature types syntax.y: arg-type = ('s' | 'S' | 'n' | 'N' | 'b' | 'B' | 'k' | 't' | 'o' | 'O'...
Definition: internal.c:202
Definition: vm.c:100
Definition: potion.h:577
#define DBG_c(...)
Definition: potion.h:250
#define DBG_t(...)
Definition: potion.h:242
the Potion VM instruction set (heavily based on Lua's)
#define PN_STR(x)
Definition: potion.h:210
the ast for Potion code in-memory
#define PN_INT(x)
Definition: potion.h:205
#define PN_ZERO
Definition: potion.h:140
#define PN_NUM(i)
Definition: potion.h:204
definition of the jit targets: x86, ppc, arm
Definition: potion.h:587
Definition: vm.c:102
#define PN_IS_REF(v)
Definition: potion.h:170
PN potion_sig_at(Potion *P, PN sig, int index)
Definition: objmodel.c:131
unsigned int PN_SIZE
Definition: potion.h:79
int arity
cached sig arity (number of args)
Definition: potion.h:460
PN potion_vm(Potion *P, PN proto, PN self, PN vargs, PN_SIZE upc, PN *upargs)
the bytecode run-loop
Definition: vm.c:594
#define PN_OP(T, A, B)
Warning: This might conflict with the typedef struct PN_OP.
Definition: ast.h:28
#define PN_TVTABLE
Definition: potion.h:119
PN lobby
root namespace
Definition: potion.h:648
#define CASE(op, block)
PNTarget potion_target_x86
#define PN_BOOL(v)
Definition: potion.h:158
#define PN_IS_CLOSURE(v)
Definition: potion.h:168
PN locals
local variables
Definition: potion.h:451
#define PN_DEREF(x)
Definition: potion.h:220
#define PN_DBL(num)
Definition: potion.h:206
void(* jmpedit)(Potion *, struct PNProto *volatile, PNAsm *volatile *, unsigned char *, int)
Definition: potion.h:593
#define PN_TEST(v)
Definition: potion.h:155
#define PN_FLEX_SIZE(N)
Definition: potion.h:231
Definition: vm.c:99
PN potion_run(Potion *P, PN code, int jit)
Definition: compile.c:1283
PN potion_obj_get(Potion *P, PN cl, PN self, PN ivar)
implements OP_GETPATH
Definition: objmodel.c:322
PN potion_obj_get_callset(Potion *P, PN obj)
get default writer
Definition: objmodel.c:239
static PN potion_sig_check(Potion *P, struct PNClosure *cl, int arity, int numargs)
Definition: vm.c:438
void potion_define_global(Potion *P, PN name, PN val)
Definition: objmodel.c:622
PN potion_parse(Potion *, PN, char *)
#define SWITCH_START(op)
#define PN_NONE
Definition: potion.h:145
#define DBG_CHECK_TUPLE(obj)
Definition: potion.h:190
unsigned char u8
Definition: internal.h:8
#define PN_MEMCPY_N(X, Y, T, N)
Definition: internal.h:22
some assembler macros
#define CASE_OP(name, args)
Definition: vm.c:219
Definition: vm.c:103
size_t potion_cp_strlen_utf8(const char *_s)
wonderful utf-8 counting trickery by colin percival
Definition: contrib.c:17
PNAsm * potion_asm_new(Potion *P)
Definition: asm.c:13
#define PN_TRUE
Definition: potion.h:142
PN potion_vm_neq(Potion *P, PN a, PN b)
Definition: vm.c:427
PN potion_obj_get_call(Potion *P, PN obj)
get the default accessor (usually "at")
Definition: objmodel.c:229
PN potion_vm_eq(Potion *P, PN a, PN b)
Definition: vm.c:416
#define PN_IS_DBL(v)
Definition: potion.h:163
a prototype is compiled source code, a closure block (lambda) non-volatile.
Definition: potion.h:445
PN potion_table_at(Potion *P, PN cl, PN self, PN key)
Definition: table.c:70
PN potion_error(Potion *P, PN msg, long lineno, long charno, PN excerpt)
Definition: internal.c:232
non-API internal parts
static PN(* pn_readline)(Potion *, PN, PN, PN)
Definition: vm.c:105
#define ASM_TPL_IMM
Definition: asm.h:17
#define PN_IS_PTR(v)
Definition: potion.h:159
const u8 args
Definition: vm.c:113
Definition: vm.c:101
PN potion_str_format(Potion *, const char *,...) __attribute__((format(printf
#define PN_ALLOC_FUNC(size)
Definition: internal.h:88
#define PN_GET(T, X)
Definition: potion.h:265
#define PN_AST2_(T, A, B)
Definition: ast.h:25
PN potion_call(Potion *P, PN cl, PN_SIZE argc, PN *volatile argv)
Definition: internal.c:143
#define PN_VM_CMP(cmp)
Definition: vm.c:412
#define PN_GET_TUPLE(t)
Definition: potion.h:267
PN potion_lick(Potion *P, PN name, PN inner, PN attr)
Definition: lick.c:11
PN_SIZE len
Definition: potion.h:577
#define PN_OP_AT(asmb, n)
Definition: opcodes.h:82
#define PN_OP_LEN(asmb)
Definition: opcodes.h:83
-d: instrumented bytecode (line stepping) or just slow runloop?
Definition: potion.h:608
int a
< the op. See vm.c http://www.lua.org/doc/jucs05.pdf
Definition: opcodes.h:71
int minargs
cached number of mandatory args, without optional
Definition: potion.h:377
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:644
#define PN_VM_NUMCMP(cmp)
Definition: vm.c:403
The potion API.
void(* local)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long, long)
Definition: potion.h:591
const struct @3 potion_ops[]
unsigned char ptr[]
Definition: potion.h:577
PN sig
signature PNTuple
Definition: potion.h:375
#define PN_TYPE(x)
Definition: potion.h:133
PN potion_vm_proto(Potion *P, PN cl, PN self,...)
entrypoint for all bytecode methods from the C api.
Definition: vm.c:159
#define PN_IS_INT(v)
Definition: potion.h:162
#define PN_VM_MATH2(name, oper)
Definition: vm.c:369
PN potion_message(Potion *P, PN rcv, PN msg)
Definition: objmodel.c:423
#define SWITCH_END
PN debugs
tree parts
Definition: potion.h:455
#define PN_QUICK_FWD(t, obj)
PN_QUICK_FWD - doing a single fwd check after a possible realloc.
Definition: potion.h:549
the central table type, based on core/khash.h
_PN(* PN_F)(Potion *, PN, PN,...)
Definition: potion.h:207
interface to various jit disassembler libs.
PN potion_obj_bitn(Potion *P, PN a)
Definition: objmodel.c:450
PN stack
size of the stack
Definition: potion.h:449
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
Definition: potion.h:772
doubles are floating point numbers stored as binary data.
Definition: potion.h:352
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
Definition: objmodel.c:82
#define PN_STRN(x, l)
Definition: potion.h:211
#define PN_AST_(T, A)
Definition: ast.h:24
void(* upvals)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long, long, int)
Definition: potion.h:592
volatile _PN PN
Definition: potion.h:81
int b
optional arg, the message
Definition: opcodes.h:73
#define PN_NIL
Definition: potion.h:139
void(* registers)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long)
Definition: potion.h:590
size_t from
Definition: asm.h:21
PN potion_vm_class(Potion *P, PN cl, PN self)
implements the class op creates a class (or type) from a closure and parent class with obj ivars ...
Definition: vm.c:203
#define JUMPS_MAX
Definition: vm.c:217
#define PN_IS_TUPLE(v)
Definition: potion.h:165
PN potion_debug(Potion *P, struct PNProto *f, PN self, PN_OP op, PN *reg, PN *stack)
Definition: vm.c:456
#define PN_TUPLE_EACH(T, I, V, B)
Definition: potion.h:279
#define PN_TUP(X)
Definition: potion.h:262
PN potion_sig_name_at(Potion *P, PN sig, int index)
Definition: objmodel.c:165
#define PN_TOUCH(x)
Definition: potion.h:222
#define PN_TUPLE_COUNT(T, I, B)
Definition: potion.h:271
void potion_fatal(char *message)
Definition: internal.c:282
#define PN_SIZE_T
Definition: config.h:28
#define PN_STR_PTR(x)
Definition: potion.h:213
#define PN_TUP0()
Definition: potion.h:261
char * potion_find_file(Potion *P, char *str, PN_SIZE str_len)
Definition: load.c:111
PN potion_object_new(Potion *P, PN cl, PN self)
Definition: objmodel.c:516
PN potion_tuple_with_size(Potion *, unsigned long)
Definition: table.c:242
#define STACK_MAX
Definition: vm.c:216
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.
Definition: opcodes.h:70
#define PN_PROTO(x)
Definition: potion.h:218