83 #if defined(POTION_JIT_TARGET) && defined(JIT_DEBUG)
84 # if defined(HAVE_LIBDISASM)
87 # if defined(HAVE_LIBUDIS86)
111 extern const struct {
116 #define STRINGIFY(_obj) ({PN str=potion_send(_obj,PN_string);str?PN_STR_PTR(str):"";})
119 #ifdef POTION_JIT_TARGET
120 #if (POTION_JIT_TARGET == POTION_X86)
122 #elif (POTION_JIT_TARGET == POTION_PPC)
124 #elif (POTION_JIT_TARGET == POTION_ARM)
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;
169 va_start(args,
self);
174 for (i=0; i <
arity; i++) {
177 ary =
PN_PUSH(ary, va_arg(args, PN));
179 PN arg = va_arg(args, PN);
184 if ((numargs && (i >= numargs))
208 PN_TUPLE_AT(ivars, i) = PN_TUPLE_AT(proto->values, PN_INT(v));
216 #define STACK_MAX 4096
217 #define JUMPS_MAX 1024
219 #define CASE_OP(name, args) case OP_##name: target->op[OP_##name]args; break;
222 long regs = 0, lregs = 0, need = 0, rsp = 0, argx = 0, protoargs = 4;
230 target->
setup(P, f, &asmb);
231 DBG_t(
"-- run-time --\n");
237 DBG_vt(
"; %d subprotos\n", tp->len);
238 for (j=0; j < tp->len; j++) {
239 PN proto2 = (
PN)tp->set[j];
243 p2args = 3 + f2->arity;
246 if (p2args > protoargs) {
247 DBG_vt(
"; extend stack from %ld to %ld\n", protoargs, p2args);
255 need = lregs + upc + 3;
259 if (((need + 1) *
sizeof(PN)) >= 0x7f)
260 DBG_c(
"Warning: %ld registers too many, used %ld, max %d.\n",
264 rsp = (need + protoargs) *
sizeof(PN);
266 target->
stack(P, f, &asmb, rsp);
273 for (i=0; i < t->len; i++) {
274 PN v = (
PN)t->set[i];
279 target->
local(P, f, &asmb, regs + num, argx);
284 DBG_t(
"; %ld locals, %ld regs, %ld upc, sig=%s\n", argx, regs, upc,
AS_STR(f->sig));
289 target->
upvals(P, f, &asmb, lregs, need, upc);
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));
300 switch (
PN_OP_AT(f->asmb, pos).code) {
301 CASE_OP(MOVE, (P, f, &asmb, pos))
302 CASE_OP(LOADK, (P, f, &asmb, pos, need))
303 CASE_OP(LOADPN, (P, f, &asmb, pos))
304 CASE_OP(SELF, (P, f, &asmb, pos, need))
306 CASE_OP(GETLOCAL, (P, f, &asmb, pos, regs))
307 CASE_OP(SETLOCAL, (P, f, &asmb, pos, regs))
308 CASE_OP(GETUPVAL, (P, f, &asmb, pos, lregs))
309 CASE_OP(SETUPVAL, (P, f, &asmb, pos, lregs))
310 CASE_OP(GLOBAL, (P, f, &asmb, pos, need))
311 CASE_OP(NEWTUPLE, (P, f, &asmb, pos, need))
312 CASE_OP(GETTUPLE, (P, f, &asmb, pos, need))
313 CASE_OP(SETTUPLE, (P, f, &asmb, pos, need))
314 CASE_OP(GETTABLE, (P, f, &asmb, pos, need))
315 CASE_OP(SETTABLE, (P, f, &asmb, pos, need))
316 CASE_OP(NEWLICK, (P, f, &asmb, pos, need))
317 CASE_OP(GETPATH, (P, f, &asmb, pos, need))
318 CASE_OP(SETPATH, (P, f, &asmb, pos, need))
319 CASE_OP(ADD, (P, f, &asmb, pos, need))
320 CASE_OP(SUB, (P, f, &asmb, pos, need))
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))
327 CASE_OP(LT, (P, f, &asmb, pos))
328 CASE_OP(LTE, (P, f, &asmb, pos))
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))
335 CASE_OP(BIND, (P, f, &asmb, pos, need))
337 CASE_OP(MSG, (P, f, &asmb, pos, need))
338 CASE_OP(JMP, (P, f, &asmb, pos, jmps, offs, &jmpc))
339 CASE_OP(TEST, (P, f, &asmb, pos))
340 CASE_OP(NOT, (P, f, &asmb, pos))
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))
345 CASE_OP(CALL, (P, f, &asmb, pos, need))
346 CASE_OP(CALLSET, (P, f, &asmb, pos, need))
348 CASE_OP(RETURN, (P, f, &asmb, pos))
349 CASE_OP(PROTO, (P, f, &asmb, &pos, lregs, need, regs))
350 CASE_OP(CLASS, (P, f, &asmb, pos, need))
356 target->
finish(P, f, &asmb);
359 #if defined(JIT_DEBUG)
366 return f->jit = (
PN_F)fn;
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])); \
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]); \
378 #if (defined(__clang__) && ((__clang_major__ > 3) \
379 || (__clang_major__ == 3 && __clang_minor__ >= 4))) \
380 || (defined(__GNUC__) && __GNUC__ >= 5)
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])); \
389 reg[op.a] = PN_NUM((long)val); \
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]); \
399 # define PN_VM_MATH3(name, oper, ov) PN_VM_MATH2(name, oper)
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]); \
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])); \
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]);
440 if (numargs < cl->minargs)
444 AS_STR(cl), arity, numargs)
445 :
potion_str_format(P,
"Not enough arguments to %s. Required %d to %d, given %d",
451 AS_STR(cl), arity, numargs), 0, 0, 0);
471 DBG_t(
"\nEntering debug loop\n");
472 DBG_vt(
"calling debug loop(src, proto)\n");
474 # ifdef DEBUG_PROTO_DEBUG_LOOP
477 if (!debug)
return PN_NUM(0);
491 # endif // DEBUG_PROTO_DEBUG_LOOP
499 #else // DEBUG_IN_C This is a hack and will go away
508 else printf(
"(:%d):\t%s\n", t->loc.lineno,
PN_STR_PTR(t->line));
515 if (str ==
PN_STR(
":c")) {
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"
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"
535 printf(
"sorry, no debugger commands yet\n");
538 else if (str && str !=
PN_STR(
"")) {
567 op = PN_OP_AT(f->asmb, pos);
568 if (op.code == OP_GETUPVAL) {
569 cl->data[i+1] = upvals[op.b];
571 cl->data[i+1] = locals[op.b] = (PN)potion_ref(P, locals[op.b]);
573 fprintf(stderr,
"** missing an upval to proto %p\n", (void *)f);
577 for (i=0; i <
PN_INT(f->stack); i++) { regs->set[i] = reg[i]; }
579 printf(
"%s\n",
AS_STR(debug_fn(P, (PN)cl, code
613 if (!handle)
potion_fatal(
"readline library not loaded");
618 DBG_t(
"\nEntering c debug mode");
619 printf(
"\nc debug (:h for help, <enter> for continue)\n");
624 memset((
void*)stack, 0,
STACK_MAX*
sizeof(PN));
625 DBG_t(
"-- run-time --\n");
633 locals = upvals + f->upvalsize;
634 reg = locals + f->localsize + 1;
637 reg[-1] = reg[0] =
self;
640 if (upc > 0 && upargs != NULL) {
642 for (i = 0; i < upc; i++) {
643 upvals[i] = upargs[i];
652 locals[num] = args[argx];
664 fprintf(stderr,
"%d", op.
b);
665 if (op.code ==
OP_DEBUG) fprintf(stderr,
"\n");
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
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: ;
688 #define SWITCH_START(op) switch (op.code) {
689 #define CASE(op, block) case OP_##op: block; break;
694 CASE(MOVE, reg[op.
a] = reg[op.
b] )
696 CASE(LOADPN, reg[op.
a] = (PN)op.
b )
697 CASE(SELF, reg[op.
a] = reg[-1] )
700 DBG_vt(
"; deref locals %d\n", op.b);
701 reg[op.a] = PN_DEREF(locals[op.b]);
703 reg[op.a] = 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]);
712 locals[op.
b] = reg[op.
a]
721 reg[op.
a] = reg[op.
b])
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;
796 if (x >= 0) reg[op.
a + x + 2] = reg[op.
b];
797 else potion_fatal(
"named parameter not found in signature");
805 reg[op.
a] = ((
struct PNVtable *)reg[op.
a])->ctor;
811 int numargs = op.
b - op.
a - 1;
815 int arity = cl->arity;
818 for (i=numargs; i < arity; i++) {
828 }
else if (((reg - stack) +
PN_INT(f->stack) + f->upvalsize + f->localsize + 8) >=
STACK_MAX) {
831 for (i = 2; i < op.
b - 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]);
837 self = reg[op.
a + 1];
838 args = ®[op.
a + 2];
840 int arity = cl->arity;
843 for (i=numargs; i < arity; i++) {
854 upargs = &cl->data[1];
855 current = reg +
PN_INT(f->stack) + 2;
857 current[-1] = (
PN)pos;
868 reg[op.
a + 1] = reg[op.
a];
884 if (current != stack) {
891 reg = current - (
PN_INT(f->stack) + 2);
892 current = reg - (f->localsize + f->upvalsize + 1);
905 unsigned areg = op.
a;
914 cl->data[i+1] = upvals[op.
b];
918 fprintf(stderr,
"** missing an upval to proto %p\n", (
void *)proto);
937 fprintf(stderr,
"\n");
939 fprintf(stderr,
"\t; %s\n",
STRINGIFY(reg[op.
a]));
#define PN_TUPLE_AT(t, n)
void(* finish)(Potion *, struct PNProto *volatile, PNAsm *volatile *)
PN asmb
assembled instructions
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
PN upvals
variables in upper scopes
PN potion_def_method(Potion *P, PN closure, PN self, PN key, PN method)
define a method for a class
bytecode (switch or cgoto)
void potion_vm_init(Potion *P)
PN potion_class(Potion *P, PN cl, PN self, PN ivars)
create a user-class (ie type)
void(* setup)(Potion *, struct PNProto *volatile, PNAsm *volatile *)
record labels to be patched
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.
PN potion_table_set(Potion *, PN, PN, PN)
helper function for potion_table_put:"put", accepts tuple or table
Potion_Flags flags
vm flags: execution model and debug flags
PN potion_bind(Potion *P, PN rcv, PN msg)
find method for given receiver and message (method lookup)
a closure is an anonymous function, without closed values,
the central vtable, see io http://www.piumarta.com/pepsi/objmodel.pdf
PN potion_obj_set(Potion *P, PN cl, PN self, PN ivar, PN value)
implements OP_SETPATH
void(* stack)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long)
int potion_sig_find(Potion *, PN, PN)
static PN potion_type_default(char type)
zero values per type
#define PN_VM_MATH3(name, oper, ov)
PN potion_ref(Potion *P, PN data)
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
char potion_type_char(PNType type)
valid signature types syntax.y: arg-type = ('s' | 'S' | 'n' | 'N' | 'b' | 'B' | 'k' | 't' | 'o' | 'O'...
the Potion VM instruction set (heavily based on Lua's)
the ast for Potion code in-memory
definition of the jit targets: x86, ppc, arm
PN potion_sig_at(Potion *P, PN sig, int index)
int arity
cached sig arity (number of args)
PN potion_vm(Potion *P, PN proto, PN self, PN vargs, PN_SIZE upc, PN *upargs)
the bytecode run-loop
#define PN_OP(T, A, B)
Warning: This might conflict with the typedef struct PN_OP.
PNTarget potion_target_x86
void(* jmpedit)(Potion *, struct PNProto *volatile, PNAsm *volatile *, unsigned char *, int)
PN potion_run(Potion *P, PN code, int jit)
PN potion_obj_get(Potion *P, PN cl, PN self, PN ivar)
implements OP_GETPATH
PN potion_obj_get_callset(Potion *P, PN obj)
get default writer
static PN potion_sig_check(Potion *P, struct PNClosure *cl, int arity, int numargs)
void potion_define_global(Potion *P, PN name, PN val)
PN potion_parse(Potion *, PN, char *)
#define DBG_CHECK_TUPLE(obj)
#define PN_MEMCPY_N(X, Y, T, N)
#define CASE_OP(name, args)
size_t potion_cp_strlen_utf8(const char *_s)
wonderful utf-8 counting trickery by colin percival
PNAsm * potion_asm_new(Potion *P)
PN potion_vm_neq(Potion *P, PN a, PN b)
PN potion_obj_get_call(Potion *P, PN obj)
get the default accessor (usually "at")
PN potion_vm_eq(Potion *P, PN a, PN b)
a prototype is compiled source code, a closure block (lambda) non-volatile.
PN potion_table_at(Potion *P, PN cl, PN self, PN key)
PN potion_error(Potion *P, PN msg, long lineno, long charno, PN excerpt)
static PN(* pn_readline)(Potion *, PN, PN, PN)
PN potion_str_format(Potion *, const char *,...) __attribute__((format(printf
#define PN_ALLOC_FUNC(size)
#define PN_AST2_(T, A, B)
PN potion_call(Potion *P, PN cl, PN_SIZE argc, PN *volatile argv)
PN potion_lick(Potion *P, PN name, PN inner, PN attr)
#define PN_OP_AT(asmb, n)
-d: instrumented bytecode (line stepping) or just slow runloop?
int a
< the op. See vm.c http://www.lua.org/doc/jucs05.pdf
int minargs
cached number of mandatory args, without optional
the global interpreter state P. currently singleton (not threads yet)
#define PN_VM_NUMCMP(cmp)
void(* local)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long, long)
const struct @3 potion_ops[]
PN potion_vm_proto(Potion *P, PN cl, PN self,...)
entrypoint for all bytecode methods from the C api.
#define PN_VM_MATH2(name, oper)
PN potion_message(Potion *P, PN rcv, PN msg)
#define PN_QUICK_FWD(t, obj)
PN_QUICK_FWD - doing a single fwd check after a possible realloc.
the central table type, based on core/khash.h
_PN(* PN_F)(Potion *, PN, PN,...)
interface to various jit disassembler libs.
PN potion_obj_bitn(Potion *P, PN a)
PN stack
size of the stack
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
doubles are floating point numbers stored as binary data.
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
void(* upvals)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long, long, int)
int b
optional arg, the message
void(* registers)(Potion *, struct PNProto *volatile, PNAsm *volatile *, long)
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 ...
PN potion_debug(Potion *P, struct PNProto *f, PN self, PN_OP op, PN *reg, PN *stack)
#define PN_TUPLE_EACH(T, I, V, B)
PN potion_sig_name_at(Potion *P, PN sig, int index)
#define PN_TUPLE_COUNT(T, I, B)
void potion_fatal(char *message)
char * potion_find_file(Potion *P, char *str, PN_SIZE str_len)
PN potion_object_new(Potion *P, PN cl, PN self)
PN potion_tuple_with_size(Potion *, unsigned long)
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.