26 #define PN_ASM1(ins, _a) f->asmb = (PN)potion_asm_op(P, (PNAsm *)f->asmb, (u8)ins, (int)_a, 0)
27 #define PN_ASM2(ins, _a, _b) f->asmb = (PN)potion_asm_op(P, (PNAsm *)f->asmb, (u8)ins, (int)_a, (int)_b)
33 {
"noop", 0}, {
"move", 2}, {
"loadk", 2}, {
"loadpn", 2}, {
"self", 1},
34 {
"newtuple", 2}, {
"gettuple", 2}, {
"settuple", 2}, {
"getlocal", 2}, {
"setlocal", 2},
35 {
"getupval", 2}, {
"setupval", 2}, {
"global", 2}, {
"gettable", 2},
36 {
"settable", 2}, {
"newlick", 2}, {
"getpath", 2}, {
"setpath", 2},
37 {
"add", 2}, {
"sub", 2}, {
"mult", 2}, {
"div", 2}, {
"mod", 2}, {
"pow", 2},
38 {
"not", 1}, {
"cmp", 2}, {
"eq", 2}, {
"neq", 2}, {
"lt", 2}, {
"lte", 2},
39 {
"gt", 2}, {
"gte", 2}, {
"bitn", 2}, {
"bitl", 2}, {
"bitr", 2}, {
"def", 2},
40 {
"bind", 2}, {
"msg", 2}, {
"jump", 1}, {
"test", 2}, {
"testjmp", 2},
41 {
"notjmp", 2}, {
"named", 2}, {
"call", 2}, {
"callset", 2}, {
"tailcall", 2},
42 {
"return", 1}, {
"proto", 2}, {
"class", 2}, {
"debug", 2}
67 for (i = 0; i < t->
len; i++) {
71 int c =
PN_INT(v); comma=0;
76 else if (c ==
':') { nextdef = 1;
81 if (nextdef) { nextdef = 0;
116 pn_printf(P, out,
".path /");
117 v = PN_TUPLE_AT(t->values, PN_INT(v));
118 potion_bytes_obj_string(P, out, v);
119 pn_printf(P, out,
" ; %u\n", i);
122 pn_printf(P, out,
".local ");
123 potion_bytes_obj_string(P, out, v);
124 pn_printf(P, out,
" ; %u\n", i);
127 pn_printf(P, out,
".upval ");
128 potion_bytes_obj_string(P, out, v);
129 pn_printf(P, out,
" ; %u\n", i);
132 pn_printf(P, out,
".value ");
133 potion_bytes_obj_string(P, out, v);
134 pn_printf(P, out,
" ; %u\n", i);
137 potion_bytes_obj_string(P, out, v);
141 const int commentoffset = 20;
142 int width =
pn_printf(P, out,
"[%*u] %-8s %d",
148 if (width < commentoffset)
149 pn_printf(P, out,
"%*s", commentoffset - width,
"");
154 switch (
PN_OP_AT(t->asmb, x).code) {
184 #define PN_REG(f, reg) \
185 if (reg >= PN_INT(f->stack)) \
186 f->stack = PN_NUM(reg + 1)
187 #define PN_ARG(n, reg) \
188 if (PN_PART(t->a[n]) == AST_EXPR && PN_PART(PN_TUPLE_AT(PN_S(t->a[n],0), 0)) == AST_LIST) { \
189 PN test = PN_S(PN_TUPLE_AT(PN_S(t->a[n],0), 0), 0); \
190 if (!PN_IS_NIL(test)) { \
191 DBG_c("expr (list %s) => %s\n", AS_STR(test), AS_STR(test)); \
192 PN_TUPLE_EACH(test, i, v, { \
193 potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg); }); \
196 potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
198 #define PN_BLOCK(reg, blk, sig) ({ \
199 PN block = potion_send(blk, PN_compile, (PN)f, sig); \
200 PN_SIZE num = PN_PUT(f->protos, block); \
201 DBG_c("protos => %u\n", num); \
202 PN_ASM2(OP_PROTO, reg, num); \
203 PN_TUPLE_EACH(((struct PNProto *)block)->upvals, i, v, { \
204 PN_SIZE numup = PN_GET(f->upvals, v); \
205 DBG_c("upvals %s <= %d\n", AS_STR(v), (int)numup); \
206 if (numup != PN_NONE) PN_ASM2(OP_GETUPVAL, reg, numup); \
207 else PN_ASM2(OP_GETLOCAL, reg, PN_GET(f->locals, v)); \
210 #define PN_UPVAL(name) ({ \
211 PN_SIZE numl = PN_GET(f->locals, name); \
212 DBG_c("locals %s <= %d\n", AS_STR(name), (int)numl); \
213 PN_SIZE numup = PN_NONE; \
214 if (numl == PN_NONE) { \
215 numup = PN_GET(f->upvals, name); \
216 if (numup == PN_NONE) { \
217 DBG_c("upvals %s <= -1\n", AS_STR(name)); \
220 while (PN_IS_PROTO(up->source)) { \
221 up = (struct PNProto *)up->source; \
222 if (PN_NONE != (numup = PN_GET(up->locals, name))) break; \
225 DBG_c("locals %s <= %d\n", AS_STR(name), (int)numup); \
226 if (numup != PN_NONE) { \
229 up->upvals = PN_PUSH(up->upvals, name); \
230 DBG_c("upvals %s =>\n", AS_STR(name)); \
231 up = (struct PNProto *)up->source; \
234 numup = PN_GET(f->upvals, name); \
235 DBG_c("upvals %s <= %d\n", AS_STR(name), (int)numup); \
240 #define PN_ARG_TABLE(args, reg, inc) potion_arg_asmb(P, f, loop, args, ®, inc)
241 #define SRC_TUPLE_AT(src,i) PN_SRC(PN_TUPLE_AT(PN_S(src,0), i))
242 #define PN_ASM_DEBUG(REG, T) REG = potion_source_debug(P, f, T, REG)
250 lineno = t->loc.lineno;
256 #define MAX_JUMPS 1024
275 DBG_c(
"ARGLIST %d %d\n", freg, sreg);
292 DBG_c(
"values %d %s => %d\n", sreg,
AS_STR(lhs->a[0]), (
int)num);
359 vPN(Source) msg = a->a[0];
406 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(a), (
int)num);
417 DBG_c(
"; call %d %d VALUE\n", reg, breg);
424 vPN(Source) lhs = t->
a[0];
431 DBG_c(
"assign expr [%lu]\n", (
_PN)c);
432 for (i = 0; i < c; i++) {
441 DBG_c(
"assign %s '%s'\n", lhs->part ==
AST_MSG?
"msg":
"query",
443 if ((first_letter & 0x80) == 0 && isupper((
unsigned char)first_letter)) {
445 DBG_c(
"values %d %s => %d\n", breg,
AS_STR(lhs->a[0]), (
int)num);
453 DBG_c(
"locals %s => %d\n",
AS_STR(lhs->a[0]), (
int)num);
455 #if 0 // store func names
459 DBG_c(
"getlocal %s %ld = %s\n",
466 DBG_c(
"values %d %s => %d\n", breg+1,
AS_STR(lhs->a[0]), (
int)num);
474 DBG_c(
"values %d %s => %d\n", breg+1,
AS_STR(lhs->a[0]), (
int)num);
477 DBG_c(
"paths %d\n", (
int)num);
487 else if (lhs->a[1] !=
PN_NIL) {
490 DBG_c(
"; callset %d %d ASSIGN\n", reg, breg);
495 DBG_c(
"; call %d %d ASSIGN\n", reg, breg);
510 DBG_c(
"setlocal %d %d\n", reg, (
int)num);
529 vPN(Source) lhs = t->
a[0];
534 DBG_c(
"locals %s => %d\n",
AS_STR(lhs->a[0]), (
int)num);
642 PN_STRN(
"self", 4), blk->loc.lineno, 0)),
643 blk->loc.lineno, blk->line));
656 PN_F sym = (
PN_F)dlsym(RTLD_DEFAULT, name);
657 DBG_c(
"extern %s => dlsym %p\n", name, sym);
659 fprintf(stderr,
"* extern %s not found. You may need to load a library first\n",
675 for (i=0; i <
arity; i++) {
680 DBG_c(
"extern %s %d-th arg => PN_INT(N)\n", name, i);
683 }
else if (arg ==
PN_STR(
"S") || arg ==
PN_STR(
"char*")) {
684 DBG_c(
"extern %s %d-th arg => PN_STR_PTR(S)\n", name, i);
688 fprintf(stderr,
"* unknown extern %s argument type qualifier\n",
708 }
else if (
PN_S(t,1) || !t->
a[2]) {
724 for (i = 0; i < l.
bjmpc; i++) {
727 for (i = 0; i < l.
cjmpc; i++) {
770 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
791 #define LOAD_ARG() PN_ARG_TABLE(PN_S(t,1), breg, 1)
812 DBG_c(
"; call %d %d MSG\n", reg, breg);
816 DBG_c(
"; call %d %d !MSG\n", reg, breg);
833 DBG_c(
"; call %d %d\n", reg, breg);
845 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
848 DBG_c(
"paths %d\n", (
int)num);
862 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
888 DBG_c(
"values %d %s => %d\n", reg+1,
AS_STR(lhs->a[0]), (
int)num);
911 #define SIG_EXPR_MSG(name,expr) \
912 if (expr->part == AST_EXPR) { \
913 vPN(Source) t = SRC_TUPLE_AT(expr, 0); \
914 if (t->part == AST_MSG) { \
916 PN_PUT(f->locals, name); \
917 DBG_c("locals %s\n", PN_STR_PTR(name)); \
918 sig = PN_PUSH(sig, name); \
920 } else { name = PN_NIL; }
948 if (__tv->
len != 0) {
949 DBG_c(
"--- sig compile ---\n");
951 for (i = 0; i < __tv->
len; i++) {
958 vPN(Source) lhs = expr->a[0];
961 DBG_c(
"sig: lhs value, computed name %s\n",
AS_STR(v));
968 }
else if (expr->part ==
AST_PIPE) {
969 vPN(Source) lhs = expr->a[0];
970 vPN(Source) rhs = expr->a[1];
977 vPN(Source) lhs = expr->a[0];
978 vPN(Source) rhs = expr->a[1];
1058 DBG_c(
"-- compile --\n");
1084 n->source = f->source;
1085 n->stack = f->stack;
1093 n->localsize = f->localsize;
1094 n->upvalsize = f->upvalsize;
1095 n->pathsize = f->pathsize;
1098 len = ((
PNAsm *)f->asmb)->len;
1107 #define READ_U8(ptr) ({u8 rpu = *ptr; ptr += sizeof(u8); rpu;})
1108 #define READ_PN(pn, ptr) ({PN rpn = *(PN *)ptr; ptr += pn; rpn;})
1109 #define READ_CONST(pn, ptr) ({ \
1110 PN val = READ_PN(pn, ptr); \
1111 if (PN_IS_PTR(val)) { \
1113 size_t len = ((val ^ 2) >> 4) - 1; \
1114 val = potion_strtod(P, (char *)ptr, len); \
1117 size_t len = (val >> 4) - 1; \
1118 val = PN_STRN((char *)ptr, len); \
1125 #define READ_TUPLE(ptr) \
1126 long i = 0, count = READ_U8(ptr); \
1127 PN tup = potion_tuple_with_size(P, (PN_SIZE)count); \
1128 for (; i < count; i++)
1129 #define READ_VALUES(pn, ptr) ({ \
1130 READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = READ_CONST(pn, ptr); \
1133 #define READ_PROTOS(pn, ptr) ({ \
1134 READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = potion_proto_load(P, (PN)f, pn, &(ptr)); \
1146 if (f->source ==
PN_NIL) f->source = up;
1184 #define WRITE_U8(un, ptr) ({*ptr = (u8)un; ptr += sizeof(u8);})
1185 #define WRITE_PN(pn, ptr) ({*(PN *)ptr = pn; ptr += sizeof(PN);})
1186 #define WRITE_CONST(val, ptr) ({ \
1187 if (PN_IS_STR(val)) { \
1188 PN count = (PN_STR_LEN(val)+1) << 4; \
1189 WRITE_PN(count, ptr); \
1190 PN_MEMCPY_N(ptr, PN_STR_PTR(val), char, PN_STR_LEN(val)); \
1191 ptr += PN_STR_LEN(val); \
1192 } else if (PN_IS_DBL(val)) { \
1193 PN str = potion_num_string(P, PN_NIL, val); \
1194 PN count = ((PN_STR_LEN(str)+1) << 4) | 2; \
1195 WRITE_PN(count, ptr); \
1196 PN_MEMCPY_N(ptr, PN_STR_PTR(str), char, PN_STR_LEN(str)); \
1197 ptr += PN_STR_LEN(str); \
1199 PN cval = (PN_IS_PTR(val) ? PN_NIL : val); \
1200 WRITE_PN(cval, ptr); \
1203 #define WRITE_TUPLE(tup, ptr) \
1204 long i = 0, count = PN_TUPLE_LEN(tup); \
1205 WRITE_U8(count, ptr); \
1206 for (; i < count; i++)
1207 #define WRITE_VALUES(tup, ptr) ({ \
1208 WRITE_TUPLE(tup, ptr) WRITE_CONST(PN_TUPLE_AT(tup, i), ptr); \
1210 #define WRITE_PROTOS(tup, ptr) ({ \
1211 WRITE_TUPLE(tup, ptr) ptr += potion_proto_dumpbc(P, PN_TUPLE_AT(tup, i), \
1212 out, (char *)ptr - PN_STR_PTR(out)); \
1224 u8 *ptr = (
u8 *)start;
1238 return (
char *)ptr - start;
1247 DBG_c(
"compile bc\n");
1266 if (backend ==
PN_STRN(
"bc", 2))
1271 DBG_c(
"loaded compile/%s\n", cb);
1275 fprintf(stderr,
"** failed loading the compile/%s module\n", cb);
1279 potion_fatal(
"external compilers disabled with SANDBOX");
1284 #ifndef POTION_JIT_TARGET
1286 fprintf(stderr,
"** potion not compiled with JIT\n");
#define PN_TUPLE_AT(t, n)
PN potion_vm(Potion *, PN, PN, PN, PN_SIZE, PN *volatile)
the bytecode run-loop
PN asmb
assembled instructions
#define PN_FLEX_NEW(N, V, T, S)
PN potion_bytes(Potion *, size_t)
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
PN upvals
variables in upper scopes
PN_AST
An AST fragment, non-volatile.
PN values
numbers, strings, etc.
#define WRITE_PN(pn, ptr)
PN_F potion_jit_proto(Potion *, PN)
a tuple is an array of PNs.
PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr)
#define READ_PROTOS(pn, ptr)
Potion_Flags flags
vm flags: execution model and debug flags
PN_SIZE void potion_bytes_obj_string(Potion *, PN, PN)
PN PN potion_byte_str(Potion *, const char *)
PN potion_sig_string(Potion *P, PN cl, PN sig)
PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options)
#define potion_method(RCV, MSG, FN, SIG)
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
#define PN_ASM_DEBUG(REG, T)
PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src)
Converts a pre-compiled potion expr to a signature tuple.
#define WRITE_CONST(val, ptr)
const struct @0 potion_ops[]
PN potion_source_load(Potion *P, PN cl, PN buf)
PN_F jit
jit function pointer
PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig)
the Potion VM instruction set (heavily based on Lua's)
the ast for Potion code in-memory
PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options)
PN potion_load(Potion *P, PN cl, PN self, PN file)
int arity
cached sig arity (number of args)
enum PN_AST part
AST type, avoid -Wswitch (aligned access: 4+4+8+4+24)
#define PN_OP(T, A, B)
Warning: This might conflict with the typedef struct PN_OP.
PN potion_proto_string(Potion *P, PN cl, PN self)
#define PN_ARG_TABLE(args, reg, inc)
PNAsm * potion_asm_op(Potion *P, PNAsm *volatile asmb, u8 ins, int _a, int _b)
PN potion_run(Potion *P, PN code, int jit)
PN potion_proto_call(Potion *P, PN cl, PN self, PN args)
PN paths
paths (instance variables)
void potion_syntax_error(Potion *P, struct PNSource *t, const char *fmt,...)
PN potion_parse(Potion *, PN, char *)
#define READ_CONST(pn, ptr)
jump table for loops, for the 2 args b and c Note: only statically allocated (max 1024) ...
#define PN_MEMCPY_N(X, Y, T, N)
PN potion_eval(Potion *P, PN bytes)
int cjmpc
count of c jumps (abc regs)
PNAsm * potion_asm_new(Potion *P)
#define PN_BLOCK(reg, blk, sig)
JIT if detected at config-time (x86, ppc)
a prototype is compiled source code, a closure block (lambda) non-volatile.
void potion_arg_asmb(Potion *P, struct PNProto *volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc)
#define SIG_EXPR_MSG(name, expr)
#define PN_ASM2(ins, _a, _b)
u8 potion_source_debug(Potion *P, struct PNProto *volatile f, struct PNSource *volatile t, u8 reg)
insert DEBUG ops for every new line
#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
the global interpreter state P. currently singleton (not threads yet)
PN_SIZE pn_printf(Potion *, PN, const char *,...) __attribute__((format(printf
#define READ_VALUES(pn, ptr)
PN potion_strcat(Potion *P, char *str, char *str2)
struct PNSource *volatile a[3]
PNTuple of 1-3 kids,.
_PN(* PN_F)(Potion *, PN, PN,...)
void potion_compiler_init(Potion *P)
int bjmpc
count of b jumps (abc regs)
#define SRC_TUPLE_AT(src, i)
PN stack
size of the stack
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos)
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
#define PN_MEMCPY(X, Y, T)
PN tree
abstract syntax tree
#define WRITE_PROTOS(tup, ptr)
void potion_source_asmb(Potion *, struct PNProto *volatile, struct PNLoop *, PN_SIZE, struct PNSource *volatile, u8)
#define PN_CALLOC_N(V, T, C)
#define WRITE_VALUES(tup, ptr)
PN source
program name or enclosing scope
PN potion_proto_clone(Potion *P, PN cl, PN self)
PN potion_proto_tree(Potion *P, PN cl, PN self)
struct PNSource::@1 loc
bitfield of fileno and lineno
#define PN_TUPLE_EACH(T, I, V, B)
void potion_fatal(char *message)
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.