17 #define RBP(x) (0x100 - ((x + 1) * sizeof(PN)))
18 #define RBPN(x) (- (int)((x + 1) * sizeof(PN)))
19 #define RBPI(x) (0x100 - ((x + 1) * sizeof(int)))
25 #define X86C(op32, op64, n, reg) op32+((reg)>15?(n)*3:0)
27 # define ASM_MOV_EBP(op, reg) \
29 DBG_v("; reg %d > 31, op 0x%x\n", (int)reg, op); \
30 ASM((op)+0x40); ASMI(RBPN(reg)); } \
31 else { ASM(op); ASM(RBP(reg)); }
33 # define ASM_MOV_EBP(op, reg) \
34 if (reg > 31) { ASM((op)+0x40); ASMI(RBPN(reg)); } \
35 else { ASM(op); ASM(RBP(reg)); }
39 #define X86_PRE() ASM(0x48)
40 #define X86_POST() ASM(0x48); ASM(0x98)
41 #define X86C(op32, op64, n, reg) op64+((reg)>31?(n)*3:0)
43 # define ASM_MOV_EBP(op, reg) \
45 DBG_v("; reg %d > 15, op 0x%x\n", (int)reg, op); \
46 ASM((op)+0x40); ASMI(RBPN(reg)); } \
47 else { ASM(op); ASM(RBP(reg)); }
49 # define ASM_MOV_EBP(op, reg) \
50 if (reg > 15) { ASM((op)+0x40); ASMI(RBPN(reg)); } \
51 else { ASM(op); ASM(RBP(reg)); }
55 #define X86_MOV_RBP(reg, x) X86_PRE(); ASM(reg); ASM_MOV_EBP(0x45,x)
57 # define X86_MOVQ(reg, x) \
58 ASM(0xC7); ASM_MOV_EBP(0x45,reg) \
61 # define X86_MOVQ(reg, x) \
62 X86_PRE(); ASM(0xb8); ASMN((PN)(x)); \
63 X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x45,reg)
65 #define TAG_PREP(tag) tag = (*asmp)->len + 1
66 #define TAG_LABEL(tag) (*asmp)->ptr[tag] = ((*asmp)->len - tag - 1)
67 #define TAG_JMPTO(tag) TAG_LABEL(tag)
69 #define TAG_JMPF(insn, tag) \
73 // cond jump fwd wide to tag, fill with TAG_JMPTOW
75 #define TAG_JMPFW(insn, tag) \
76 ASM(0x0f); ASM(insn); \
77 TAG_PREP4(tag); ASMI(0);
78 #define TAG_JMPTOW(tag) TAG_LABEL4(tag)
80 #define TAG_JMPFW(insn, tag) TAG_JMPF(insn, tag)
81 #define TAG_JMPTOW(tag) TAG_LABEL(tag)
84 #define TAG_JMPB(insn, tag) \
85 if (tag > (*asmp)->len) { \
86 potion_fatal("jmp fw"); \
87 } else if ((*asmp)->len - tag > 127) { \
90 ASMI(tag - (*asmp)->len - 2); \
93 ASM(tag - (*asmp)->len - 2); \
95 #define TAG_JMPTOB(tag) tag = (*asmp)->len
96 #define TAG_PREP4(tag) tag = (*asmp)->len
97 #define TAG_LABEL4(tag) ({ int* ptr = (int*)((*asmp)->ptr + tag); \
98 *ptr = (*asmp)->len - tag - 4; })
104 #define X86_MATH(two, dbl_func, ops) ({ \
105 int dbl_a, dbl_a1, end_b; \
106 X86_MOV_RBP(0x8B, op.a); \
107 if (two) { X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55,op.b) } \
108 ASM(0xF6); ASM(0xC0); ASM(0x01); \
109 TAG_PREP(dbl_a); ASM(0x74); ASM(0); \
110 if (two) { ASM(0xF6); ASM(0xC2); ASM(0x01); } \
111 if (two) { TAG_PREP(dbl_a1); ASM(0x74); ASM(0); } \
113 TAG_PREP(end_b); ASM(0xEB); ASM(0); \
114 TAG_LABEL(dbl_a); if (two) { TAG_LABEL(dbl_a1); } \
115 X86_ARGO(start - 3, 0); \
118 X86_PRE(); ASM(0xB8); ASMN(dbl_func); \
119 ASM(0xFF); ASM(0xD0); \
121 X86_MOV_RBP(0x89, op.a) \
133 #define X86_NUMCMP(iop, xop, xmms) \
134 int dbl_a, dbl_b, cmp_dbl, true_1, true_2, false_; \
135 X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55,op.a) \
136 X86_MOV_RBP(0x8B, op.b); \
138 TAG_PREP(dbl_b); ASM(0x74);ASM(0); \
139 ASMS("\xF6\xC2\x01"); \
140 TAG_PREP(dbl_a); ASM(0x74);ASM(0); \
142 X86_PRE(); ASM(0x39); ASM(0xC2); \
143 TAG_PREP(true_1); ASM(iop); ASM(0); \
144 TAG_PREP(false_); ASM(0xEB); ASM(0); \
149 ASMS("\xf2\x0f\x10\x42");ASM(PN_SIZE_T); \
150 ASMS("\x66\x0f\xef\xc9"); \
151 X86_PRE(); ASMS("\xd1\xf8"); \
152 ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc8"); \
153 TAG_PREP(cmp_dbl); ASM(0xEB);ASM(0); \
156 ASMS("\xf2\x0f\x10\x48");ASM(PN_SIZE_T); \
157 ASMS("\xF6\xC2\x01"); \
158 ASM(0x74);ASM(X86C(12,14, 0,0)); \
159 ASMS("\x66\x0f\xef\xc0"); \
160 X86_PRE(); ASMS("\xd1\xfa"); \
161 ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc2"); \
162 ASM(0xEB); ASM(X86C(5,5, 0,0)); \
163 ASMS("\xf2\x0f\x10\x42");ASM(PN_SIZE_T); \
165 TAG_LABEL(cmp_dbl); ASMS(xmms); \
166 TAG_PREP(true_2); ASM(xop); ASM(0); \
167 TAG_LABEL(false_); X86_MOVQ(op.a, PN_FALSE); \
168 ASM(0xEB); ASM(X86C(7,14, 1,op.a)); \
169 TAG_LABEL(true_1); TAG_LABEL(true_2); \
170 X86_MOVQ(op.a, PN_TRUE);
174 void x86_cmp(
Potion *P,
PNAsm *
volatile * asmp,
PN_OP op,
unsigned char iop,
unsigned char nop) {
175 int l23,l2,l5,l7,l8,l9,l12,l14,l16,l24,_end,_end1;
192 ASMS(
"\x83\x38\xfe");
\
198 "\x3d\x01\x00\x25\x00");
\
207 ASMS(
"\x83\x38\xfe");
\
213 "\x3d\x01\x00\x25\x00");
\
219 ASMS(
"\x66\x0f\xef\xc9");
\
227 ASMS(
"\x66\x0f\xef\xc0");
\
231 ASMS(
"\x66\x0f\x2e\xc8");
\
238 ASMS(
"\xf2\x0f\x10\x48\x08");
\
244 ASMS(
"\xf2\x0f\x10\x40\x08");
\
250 #define X86_ARGO(regn, argn) potion_x86_c_arg(P, asmp, 1, regn, argn)
251 #define X86_ARGO_IMM(regn, argn) potion_x86_c_arg(P, asmp, 2, regn, argn)
252 #define X86_ARGI(regn, argn) potion_x86_c_arg(P, asmp, 0, regn, argn)
253 #define TAG_JMP(jpos) \
255 if ((int)jpos >= (int)pos) { \
256 jmps[*jmpc].from = asmp[0]->len; \
258 jmps[*jmpc].to = jpos + 1; \
260 } else if ((int)jpos < (int)pos) { \
261 ASMI(offs[jpos + 1] - ((asmp[0]->len) + 4)); \
267 #define X86_DEBUG() \
268 X86_PRE(); ASM(0xB8); ASMN(potion_x86_debug); \
275 _PN rax, rcx, rdx, *rbp, *sp;
277 #if POTION_X86 == POTION_JIT_TARGET
279 __asm__ (
"mov %%eax, %0;"
281 __asm__ (
"mov %%ecx, %0;"
283 __asm__ (
"mov %%edx, %0;"
285 __asm__ (
"mov %%ebp, %0;"
288 __asm__ (
"mov %%rax, %0;"
290 __asm__ (
"mov %%rcx, %0;"
292 __asm__ (
"mov %%rdx, %0;"
294 __asm__ (
"mov %%rbp, %0;"
297 printf(
"RAX = 0x%lx (0x%x)\n", rax,
potion_type(rax));
298 printf(
"RCX = 0x%lx (0x%x)\n", rcx,
potion_type(rcx));
299 printf(
"RDX = 0x%lx (0x%x)\n", rdx,
potion_type(rdx));
303 printf(
"Potion: %p (%p)\n", P, &P);
307 rbp = (
unsigned long *)*sp;
308 if (rbp > sp - 2 && sp[2] == (
PN)P) {
309 printf(
"RBP = 0x%lx (0x%lx), SP = 0x%lx\n", (
PN)rbp, *rbp, (
PN)sp);
311 printf(
"STACK[%d] = 0x%lx (0x%x)\n", n++, *sp,
PN_TYPE(*sp));
333 ASMS(
"\x89\x14\x24");
344 ASMS(
"\x89\x54\x24");
ASM(argn *
sizeof(
PN));
425 int rsp =
X86C(16,0,0,0)+((need-
X86C(8,0,0,0)+15)&~(15));
456 for (upi = 0; upi < upc; upi++) {
457 int n =
sizeof(
struct PNClosure) + ((upi + 1) *
sizeof(
PN));
460 if (n >= 0x80) {
ASM(0x80);
ASMI(n); }
461 else {
ASM(0x40);
ASM(n); }
467 *((
int *)asmj) = dist;
492 + (op.
b *
sizeof(
PN)));
511 "\x75");
ASM(
X86C(19,20, 0,0));
531 "\x75");
ASM(
X86C(19,20, 0,0));
642 if (op.
b > op.
a + 1) {
806 ASMS(
"\x8D\x44\x00\x01");
819 ASMS(
"\x8D\x44\x00\x01");
860 int false1, false2, true1;
898 DBG_t(
"; notjmp %d => %d\n", op.
a, op.
b);
910 DBG_t(
"; named %d %d\n", op.
a, op.
b);
925 DBG_v(
"named: mov %%rdx -A=%d(%%rbp,%%rax,8)\n", op.
a + 2);
937 int argc = op.
b - op.
a;
938 int i, tag_a1, tag_a2, tag_b, tag_c, tag_d;
993 DBG_t(
"; call %ld[0] %d[1] ", start-3, op.
a);
994 for (i=2; i <= argc+1; i++) {
995 DBG_t(
"%d[%d] ", op.
a + i - 1, i);
1001 int arity = c->arity;
1002 if (arity && (argc-1 < arity)) {
1003 for (i = argc+1; i <= arity+1; i++) {
1073 fprintf(stderr,
"** missing an upval to proto %p\n", (
void *)proto);
1077 n =
sizeof(
struct PNClosure) + (sizeof(PN) * (i + 1));
1078 if (n >= 0x80) {
ASM(0x90);
ASMI(n); }
1079 else {
ASM(0x50);
ASM(n); }
#define PN_TUPLE_AT(t, n)
PN asmb
assembled instructions
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
#define X86_MOV_RBP(reg, x)
void potion_x86_bitr(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_def_method(Potion *P, PN closure, PN self, PN key, PN method)
define a method for a class
void potion_x86_call(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
record labels to be patched
klib hash table library based on double hashing http://en.wikipedia.org/wiki/Double_hashing ...
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
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
void potion_x86_setlocal(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long regs)
PN potion_obj_set(Potion *P, PN cl, PN self, PN ivar, PN value)
implements OP_SETPATH
int potion_sig_find(Potion *, PN, PN)
void potion_x86_getpath(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
static PN potion_type_default(char type)
zero values per type
void potion_x86_test_asm(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, int test)
void potion_x86_mcache(Potion *P, vPN(Vtable) vt, PNAsm *volatile *asmp)
#define X86_NUMCMP(iop, xop, xmms)
void potion_x86_settuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_not(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
void potion_x86_def(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_newlick(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_local(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long reg, long arg)
void potion_x86_registers(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long start)
void potion_x86_test(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_f_protos(Potion *P, PN cl, PN i)
PN potion_ref(Potion *P, PN data)
void potion_x86_loadk(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_jmpedit(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, unsigned char *asmj, int dist)
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
void potion_x86_lt(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
void potion_x86_testjmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
int arity
cached number of declared args, including optional
void potion_x86_setupval(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long lregs)
void potion_x86_getlocal(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long regs)
void potion_x86_move(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_obj_bitl(Potion *P, PN a, PN b)
the Potion VM instruction set (heavily based on Lua's)
void potion_x86_setup(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp)
PN potion_sig_at(Potion *P, PN sig, int index)
#define X86_ARGI(regn, argn)
PN potion_num_pow(Potion *, PN, PN, PN)
void potion_x86_div(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
standard objects act like C structs the fields are defined by the type and it's a fixed size...
void potion_x86_callset(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define ASM_MOV_EBP(op, reg)
void potion_x86_add(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define X86_MATH(two, dbl_func, ops)
#define X86_ARGO(regn, argn)
void potion_x86_bind(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_sub(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_pow(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_f_values(Potion *P, PN cl)
void potion_x86_tailcall(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_obj_get(Potion *P, PN cl, PN self, PN ivar)
implements OP_GETPATH
void potion_x86_ivars(Potion *P, PN ivars, PNAsm *volatile *asmp)
void potion_x86_bitl(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_obj_get_callset(Potion *P, PN obj)
get default writer
void potion_define_global(Potion *P, PN name, PN val)
PN potion_obj_sub(Potion *P, PN a, PN b)
PN potion_obj_add(Potion *P, PN a, PN b)
void potion_x86_bitn(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_self(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define TAG_JMPF(insn, tag)
void potion_x86_notjmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
static void potion_x86_c_arg(Potion *P, PNAsm *volatile *asmp, int out, int regn, int argn)
mimick c calling convention
void potion_x86_mult(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_eq(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_obj_mult(Potion *P, PN a, PN b)
void potion_x86_message(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_obj_get_call(Potion *P, PN obj)
get the default accessor (usually "at")
PN potion_tuple_push(Potion *, PN, PN)
a prototype is compiled source code, a closure block (lambda) non-volatile.
PN potion_table_at(Potion *P, PN cl, PN self, PN key)
#define X86_ARGO_IMM(regn, argn)
PN potion_obj_bitr(Potion *P, PN a, PN b)
void potion_x86_finish(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp)
void potion_x86_rem(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_gt(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
void potion_x86_cmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_vm_class(Potion *, PN, PN)
implements the class op creates a class (or type) from a closure and parent class with obj ivars ...
#define kh_val(name, h, x)
void potion_x86_lte(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_lick(Potion *P, PN name, PN inner, PN attr)
void potion_x86_gettable(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_settable(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define PN_OP_AT(asmb, n)
void potion_x86_upvals(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long lregs, long start, int upc)
#define X86C(op32, op64, n, reg)
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 potion_obj_rem(Potion *P, PN a, PN b)
#define kh_key(name, h, x)
PN potion_tuple_empty(Potion *)
void potion_x86_method(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE *pos, long lregs, long start, long regs)
PN potion_vm_neq(Potion *, PN, PN)
PN potion_message(Potion *P, PN rcv, PN msg)
void potion_x86_neq(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
static PNType potion_type(PN obj)
either immediate (NUM,BOOL,NIL) or a fwd
#define TAG_JMPB(insn, tag)
the central table type, based on core/khash.h
void potion_x86_loadpn(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_obj_bitn(Potion *P, PN a)
PN stack
size of the stack
void potion_x86_named(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
int b
optional arg, the message
void potion_x86_return(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
void potion_x86_jmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
void potion_x86_stack(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long need)
void potion_x86_getupval(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long lregs)
void potion_x86_global(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_gettuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define kh_exist(name, h, x)
void potion_x86_setpath(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
#define PN_TUPLE_EACH(T, I, V, B)
void potion_x86_newtuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
PN potion_vm_eq(Potion *, PN, PN)
#define PN_TUPLE_COUNT(T, I, B)
void potion_x86_class(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
void potion_x86_gte(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
PN potion_object_new(Potion *P, PN cl, PN self)
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.
PN potion_obj_div(Potion *P, PN a, PN b)