p2  0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vm-x86.c
Go to the documentation of this file.
1 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <math.h>
10 #include "p2.h"
11 #include "internal.h"
12 #include "opcodes.h"
13 #include "asm.h"
14 #include "khash.h"
15 #include "table.h"
16 
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)))
20 
21 #if PN_SIZE_T != 8
22 #define X86_PRE_T 0
23 #define X86_PRE()
24 #define X86_POST()
25 #define X86C(op32, op64, n, reg) op32+((reg)>15?(n)*3:0)
26 #ifdef DEBUG
27 # define ASM_MOV_EBP(op, reg) \
28  if (reg > 31) { \
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)); }
32 #else
33 # define ASM_MOV_EBP(op, reg) /* 2,5 */ \
34  if (reg > 31) { ASM((op)+0x40); ASMI(RBPN(reg)); } \
35  else { ASM(op); ASM(RBP(reg)); }
36 #endif
37 #else
38 #define X86_PRE_T 1
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)
42 # ifdef DEBUG
43 # define ASM_MOV_EBP(op, reg) \
44  if (reg > 15) { \
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)); }
48 # else
49 # define ASM_MOV_EBP(op, reg) /* 2,5 */ \
50  if (reg > 15) { ASM((op)+0x40); ASMI(RBPN(reg)); } \
51  else { ASM(op); ASM(RBP(reg)); }
52 # endif
53 #endif
54 
55 #define X86_MOV_RBP(reg, x) X86_PRE(); ASM(reg); ASM_MOV_EBP(0x45,x)
56 #if PN_SIZE_T != 8
57 # define X86_MOVQ(reg, x) /* size = 7,10 */ \
58  ASM(0xC7); ASM_MOV_EBP(0x45,reg) /* movl -A(%rbp) */ \
59  ASMI((PN)(x))
60 #else
61 # define X86_MOVQ(reg, x) /* size = 14,17 */ \
62  X86_PRE(); ASM(0xb8); ASMN((PN)(x)); /* movq x, %rax */ \
63  X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x45,reg) /* movq %rax, -A(%rbp) */
64 #endif
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)
68 // cond jump fwd to tag, fill with TAG_JMPTO
69 #define TAG_JMPF(insn, tag) \
70  TAG_PREP(tag); \
71  ASM(insn); \
72  ASM(0); \
73 // cond jump fwd wide to tag, fill with TAG_JMPTOW
74 #if PN_SIZE_T == 8
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)
79 #else
80 #define TAG_JMPFW(insn, tag) TAG_JMPF(insn, tag)
81 #define TAG_JMPTOW(tag) TAG_LABEL(tag)
82 #endif
83 // cond jump back to tag, mark with TAG_JMPTOB
84 #define TAG_JMPB(insn, tag) \
85  if (tag > (*asmp)->len) { \
86  potion_fatal("jmp fw"); \
87  } else if ((*asmp)->len - tag > 127) { /* jx long */ \
88  ASM(0x0f); \
89  ASM(insn + 0x10); \
90  ASMI(tag - (*asmp)->len - 2); \
91  } else { /* jx short */ \
92  ASM(insn); \
93  ASM(tag - (*asmp)->len - 2); \
94  }
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; })
99 
100 // TODO refactor to use named TAGs
101 // TODO optimize into seperate int and dbl variants
102 // TODO check num type for the dbl case
103 // math binop for 2 numbers, int (inlined) or double (via call)
104 #define X86_MATH(two, dbl_func, ops) ({ \
105  int dbl_a, dbl_a1, end_b; \
106  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %eax */ \
107  if (two) { X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55,op.b) } /* mov -B(%rbp) %edx */ \
108  ASM(0xF6); ASM(0xC0); ASM(0x01); /* test 0x1 %al */ \
109  TAG_PREP(dbl_a); ASM(0x74); ASM(0); /* je [a] */ \
110  if (two) { ASM(0xF6); ASM(0xC2); ASM(0x01); } /* test 0x1 %dl */ \
111  if (two) { TAG_PREP(dbl_a1); ASM(0x74); ASM(0); /* je [a] */ } \
112  ops; /* add, sub, ... */ \
113  TAG_PREP(end_b); ASM(0xEB); ASM(0); /* jmp [b] */ \
114  TAG_LABEL(dbl_a); if (two) { TAG_LABEL(dbl_a1); } \
115  X86_ARGO(start - 3, 0); /* [a]: mov &P 0(%esp) */ \
116  X86_ARGO(op.a, 1); /* mov &CL 1(%esp) */ \
117  X86_ARGO(op.b, 2); /* mov B 2(%esp) */ \
118  X86_PRE(); ASM(0xB8); ASMN(dbl_func); /* mov &dbl_func %rax */ \
119  ASM(0xFF); ASM(0xD0); /* callq %rax */ \
120  TAG_LABEL(end_b); \
121  X86_MOV_RBP(0x89, op.a) /* [b]: mov -B(%rbp) %eax */ \
122  })
123 // cmp 2 numbers, int or double. eq/neq/gt/ge/lt/le, both inlined (requires SSE)
124 // iop: jl, jg, jle, jge, je, jne for normal cmp comparisons
125 // xop: jb, jbe", jae, ja, ... for SSE ucomisd comparisons.
126 // TODO we also need to check jp for PF (parity) if one number is nan, to force false.
127 // TODO optimize into seperate int and dbl variants
128 // TODO probe cpu for sse2 at init, and fallback to math calls if not.
129 // maybe create seperate so's with and without sse. and load the best at init
130 // TODO check num type for the dbl case
131 // TODO optimize j? true, set false, jmp true, set true
132 // => movzbl %al,edx;lea 0x2(,%rdx,4),%rdx;mov %rdx,-A(%rbp)
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) /* mov -A(%rbp) %rdx */ \
136  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
137  ASMS("\xA8\x01"); /* test $1, %al */ \
138  TAG_PREP(dbl_b); ASM(0x74);ASM(0); /* je [dbl_b] */ \
139  ASMS("\xF6\xC2\x01"); /* test $1, %dl */ \
140  TAG_PREP(dbl_a); ASM(0x74);ASM(0); /* je [dbl_a] */ \
141  /* cmp both int */ \
142  X86_PRE(); ASM(0x39); ASM(0xC2); /* both_int: cmp %rax, %rdx */ \
143  TAG_PREP(true_1); ASM(iop); ASM(0); /* j? [true] */ \
144  TAG_PREP(false_); ASM(0xEB); ASM(0); /* jmp [false] */ \
145  \
146  /* convert 1 or 2 to dbl, only with sse2. all amd64 have sse2 */ \
147  /* TODO: so if 32bit without sse2 call the math func instead */ \
148  TAG_LABEL(dbl_a); /* #dbl_a: b=int + a=dbl */ \
149  ASMS("\xf2\x0f\x10\x42");ASM(PN_SIZE_T); /* movsd 8(%rdx), %xmm0 [a] */ \
150  ASMS("\x66\x0f\xef\xc9"); /* pxor %xmm1, %xmm1 */ \
151  X86_PRE(); ASMS("\xd1\xf8"); /* sar %rax */ \
152  ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc8"); /* cvtsi2sd %rax, %xmm1 [b] */ \
153  TAG_PREP(cmp_dbl); ASM(0xEB);ASM(0); /* jmp [cmp_dbl] */ \
154  \
155  TAG_LABEL(dbl_b); /* #b dbl, a? */ \
156  ASMS("\xf2\x0f\x10\x48");ASM(PN_SIZE_T); /* movsd 8(%rax), %xmm1 [b] */ \
157  ASMS("\xF6\xC2\x01"); /* test $1, %dl */ \
158  ASM(0x74);ASM(X86C(12,14, 0,0)); /* je +cvt */ \
159  ASMS("\x66\x0f\xef\xc0"); /* pxor %xmm0, %xmm0 */ \
160  X86_PRE(); ASMS("\xd1\xfa"); /* sar %rdx */ \
161  ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc2"); /* cvtsi2sd %rdx, %xmm0 [a] */ \
162  ASM(0xEB); ASM(X86C(5,5, 0,0)); /* jmp [cmp_dbl] */ \
163  ASMS("\xf2\x0f\x10\x42");ASM(PN_SIZE_T); /* movsd 8(%rdx), %xmm0 [a] */ \
164  /* cmp dbl */ \
165  TAG_LABEL(cmp_dbl); ASMS(xmms); /* ucomisd xmm0<=>xmm1; */ \
166  TAG_PREP(true_2); ASM(xop); ASM(0); /* j? [true] */ \
167  TAG_LABEL(false_); X86_MOVQ(op.a, PN_FALSE); /* false: -A(%rbp) = FALSE */ \
168  ASM(0xEB); ASM(X86C(7,14, 1,op.a)); /* jmp [+true] */ \
169  TAG_LABEL(true_1); TAG_LABEL(true_2); \
170  X86_MOVQ(op.a, PN_TRUE); /* true: -A(%rbp) = TRUE */
171 
172 #if 0
173 // eq/neq: cmp 2 atoms. cmp the dbl value if both are double or the immediate words.
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;
176  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %rax */ \
177  ASMS("\xA8\x01"); /* testb $1, %al */ \
178  TAG_JMPF(0x74, l23); /* je l23 */ \
179  TAG_JMPTOB(l2); \
180  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55,op.a) /* mov -A(%rbp) %rdx */ \
181  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
182  X86_PRE(); ASM(0x39); ASM(0xC2); /* cmpq %rax, %rdx */ \
183  TAG_JMPF(0x74, l12); /* je l12 */ \
184  TAG_JMPTOB(l9); \
185  X86_MOVQ(op.a, PN_FALSE); /* movl FALSE, -A(%rbp) */ \
186  TAG_PREP(_end); ASM(0xE9); ASMI(0); /* jmp [_end] */ \
187  TAG_JMPTO(l23); \
188  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %rax */ \
189  X86_PRE(); ASM(0xa9), ASMI(-8); /* testq $-8, %rax */ \
190  TAG_JMPB(0x74, l2); /* je l2 */ \
191  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %rax */ \
192  ASMS("\x83\x38\xfe"); /* cmpl $-2, (%rax) (is_ptr?) */ \
193  TAG_JMPF(0x75, l14); /* jne l14 */ \
194  X86_PRE();ASMS("\x8b\x40");ASM(PN_SIZE_T); /* movl 8(%rax), %rax */ \
195  TAG_JMPTO(l14); \
196  ASMS("\x8b\x00" /* movl (%rax), %eax */ \
197  "\x83\xe0\xfd" /* andl $-0x3, %eax */ \
198  "\x3d\x01\x00\x25\x00"); /* cmpl $0x250001, %eax */ \
199  TAG_JMPB(0x75, l2); /* jne l2 */ \
200  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
201  ASMS("\xA8\x01"); /* testb $1, %al */ \
202  TAG_JMPB(0x75, l2); /* jne l2 */ \
203  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
204  X86_PRE(); ASM(0xa9), ASMI(-8); /* testq $-8, %rax */ \
205  TAG_JMPB(0x74, l2); /* je l2 */ \
206  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
207  ASMS("\x83\x38\xfe"); /* cmpl $-2, (%rax) (is_ptr?) */ \
208  TAG_JMPF(0x75, l16); /* jne l16 */ \
209  X86_PRE();ASMS("\x8b\x40");ASM(PN_SIZE_T); /* movl 8(%rax), %rax */ \
210  TAG_JMPTO(l16); \
211  ASMS("\x8b\x00" /* movl (%rax), %eax */ \
212  "\x83\xe0\xfd" /* andl $-0x3, %eax */ \
213  "\x3d\x01\x00\x25\x00"); /* cmpl $0x250001, %eax */ \
214  TAG_JMPB(0x75, l2); /* jne l2 */ \
215  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %rax */ \
216  ASMS("\xA8\x01"); /* testb $1, %al */ \
217  X86_MOV_RBP(0x8B, op.a); /* mov -A(%rbp) %rax */ \
218  TAG_JMPF(0x74, l5); /* je l5 */ \
219  ASMS("\x66\x0f\xef\xc9"); /* pxor %xmm1, %xmm1 */ \
220  X86_PRE();ASMS("\xd1\xf8"); /* sarq %rax */ \
221  ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc8"); /* cvtsi2sd %rax, %xmm1 [a] */ \
222  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
223  ASMS("\xA8\x01"); /* testb $1, %al */ \
224  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
225  TAG_JMPF(0x74, l7); /* je l7 */ \
226  TAG_JMPTOB(l24); \
227  ASMS("\x66\x0f\xef\xc0"); /* pxor %xmm0, %xmm0 */ \
228  X86_PRE();ASMS("\xd1\xf8"); /* sarq %rax */ \
229  ASM(0xF2);X86_PRE();ASMS("\x0f\x2a\xc0"); /* cvtsi2sd %rax, %xmm0 [b] */ \
230  TAG_JMPTOB(l8); \
231  ASMS("\x66\x0f\x2e\xc8"); /* ucomisd xmm0, xmm1; */ \
232  TAG_JMPB(0x7a, l9); /* jp [ret_false] # wide */ \
233  TAG_JMPB(nop, l9); /* jne [ret_false] # wide (negated iop) */ \
234  TAG_JMPTO(l12); /* true */ \
235  X86_MOVQ(op.a, PN_TRUE); /* true: -A(%rbp) = TRUE */ \
236  TAG_PREP(_end1); ASM(0xEB); ASM(0); /* jmp [_end] */ \
237  TAG_JMPTO(l5); \
238  ASMS("\xf2\x0f\x10\x48\x08"); /* movsd 0x8(%rax), %xmm1 */ \
239  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
240  ASMS("\xA8\x01"); /* testb $1, %al */ \
241  X86_MOV_RBP(0x8B, op.b); /* mov -B(%rbp) %rax */ \
242  TAG_JMPB(0x75, l24); /* je l24 */ \
243  TAG_JMPTO(l7); \
244  ASMS("\xf2\x0f\x10\x40\x08"); /* movsd 0x8(%rax), %xmm0 */ \
245  TAG_JMPB(0xeb, l8); /* jmp l8 */ \
246  TAG_JMPTOW(_end); TAG_JMPTO(_end1);
247 }
248 #endif
249 
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) \
254  ASM(0xE9); \
255  if ((int)jpos >= (int)pos) { \
256  jmps[*jmpc].from = asmp[0]->len; \
257  ASMI(0); \
258  jmps[*jmpc].to = jpos + 1; \
259  *jmpc = *jmpc + 1; \
260  } else if ((int)jpos < (int)pos) { \
261  ASMI(offs[jpos + 1] - ((asmp[0]->len) + 4)); \
262  } else { \
263  ASMI(0); \
264  }
265 
266 // ASM(0xcc); int3 trap: __asm__("int3");
267 #define X86_DEBUG() \
268  X86_PRE(); ASM(0xB8); ASMN(potion_x86_debug); \
269  ASM(0xFF); ASM(0xD0)
270 
271 // TODO: finish jit backtraces using this
273  Potion *P;
274  int n = 0;
275  _PN rax, rcx, rdx, *rbp, *sp;
276 
277 #if POTION_X86 == POTION_JIT_TARGET
278 #if PN_SIZE_T != 8
279  __asm__ ("mov %%eax, %0;"
280  :"=r"(rax));
281  __asm__ ("mov %%ecx, %0;"
282  :"=r"(rcx));
283  __asm__ ("mov %%edx, %0;"
284  :"=r"(rdx));
285  __asm__ ("mov %%ebp, %0;"
286  :"=r"(sp));
287 #else
288  __asm__ ("mov %%rax, %0;"
289  :"=r"(rax));
290  __asm__ ("mov %%rcx, %0;"
291  :"=r"(rcx));
292  __asm__ ("mov %%rdx, %0;"
293  :"=r"(rdx));
294  __asm__ ("mov %%rbp, %0;"
295  :"=r"(sp));
296 #endif
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));
300 #endif
301 
302  P = (Potion *)sp[2];
303  printf("Potion: %p (%p)\n", P, &P);
304 
305 again:
306  n = 0;
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);
310  while (sp < rbp) {
311  printf("STACK[%d] = 0x%lx (0x%x)\n", n++, *sp, PN_TYPE(*sp));
312  sp++;
313  }
314  goto again;
315  }
316 }
317 
324 static void potion_x86_c_arg(Potion *P, PNAsm * volatile *asmp, int out, int regn, int argn) {
325  // need to address -(x)%ebp: max regn=29/14
326  // assert(((regn + 1) * sizeof(PN)) < 0x7f);
327 #if PN_SIZE_T != 8
328  // IA-32 cdecl ABI, non-microsoft only. TODO: win32 stdcall for the w32api ffi
329  if (argn == 0) {
330  // OPT: the first argument is always (Potion *)
331  if (!out) {
332  ASM(0x8b); ASM(0x55); ASM(2 * sizeof(PN)); //mov argn(%ebp), %edx
333  ASMS("\x89\x14\x24"); //mov %edx, (%esp)
334  }
335  }
336  else {
337  if (out == 2) {
338  ASM(0xc7); ASM(0x44); ASM(0x24); ASM(argn * sizeof(PN)); ASMI(regn); //mov $regn, argn(%esp)
339  } else if (out) {
340  ASM(0x8b); ASM_MOV_EBP(0x55,regn) //mov -0x8(%ebp), %edx
341  }
342  if (!out) argn += 2;
343  if (out == 1) {
344  ASMS("\x89\x54\x24"); ASM(argn * sizeof(PN));//mov %edx, argn(%esp)
345  } else if (!out) {
346  ASM(0x8b); ASM(0x55); ASM(argn * sizeof(PN)); //mov argn(%ebp), %edx
347  }
348  if (!out) {
349  ASM(0x89); ASM_MOV_EBP(0x55,regn) //mov %edx, regn(%ebp)
350  }
351  }
352 #else
353  // sysv amd64 only (rdi,rsi,rdx,rcx,r8,r9), windows msvc not supported (rcx,rdx,r8,r9)
354  // xmm0-7 not yet
355  switch (argn) {
356  case 0: //rdi Potion *P
357  if (out == 2) { // unused - mov $regn, %rdi
358  X86_PRE(); ASM(0xc7); ASM(0xc7); ASMI(regn);
359  } else {
360  X86_PRE(); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x7d,regn) // mov -regn(%rbp), %rdi
361  }
362  break;
363  case 1: //rsi PN cl
364  if (out == 2) { // unused - mov $regn, %rsi
365  X86_PRE(); ASM(0xc7); ASM(0xc6); ASMI(regn);
366  } else { // mov -regn(%rbp), %rsi
367  X86_PRE(); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x75,regn)
368  }
369  break;
370  case 2: //rdx self
371  if (out == 2) { // unused - mov $regn, %rdx
372  X86_PRE(); ASM(0xc7); ASM(0xc2); ASMI(regn);
373  } else { // mov -regn(%rbp), %rdx
374  X86_PRE(); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x55,regn)
375  }
376  break;
377  case 3: //rcx
378  if (out == 2) { // 1st default arg - mov $regn, %rcx
379  X86_PRE(); ASM(0xc7); ASM(0xc1); ASMI(regn);
380  } else { // mov -regn(%rbp), %rcx
381  X86_PRE(); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x4d,regn)
382  }
383  break;
384  case 4: //r8
385  if (out == 2) { // 2nd default arg - mov $regn, %r8
386  ASMS("\x49\xc7\xc0"); ASMI(regn);
387  } else { // mov -regn(%rbp), %r8
388  ASM(0x4c); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x45,regn)
389  }
390  break;
391  case 5: //r9
392  if (out == 2) { // 3rd default arg - mov $regn, %r9
393  ASMS("\x49\xc7\xc1"); ASMI(regn);
394  } else { // mov -regn(%rbp), %r9
395  ASM(0x4c); ASM(out ? 0x8b : 0x89); ASM_MOV_EBP(0x4d,regn)
396  }
397  break;
398  default: // can only pass max 6 arg via regs, rest on stack
399  if (out) {
400  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x5d,regn) // mov %rbp(A) %rbx
401  if (argn == 6) {
402  X86_PRE(); ASMS("\x89\x1c\x24"); // mov %rbx (%rsp)
403  } else {
404  X86_PRE(); ASMS("\x89\x5c\x24"); ASM((argn - 6) * sizeof(PN)); // mov %rbx N(%rsp)
405  }
406  } else {
407  X86_PRE(); ASM(0x8b); ASM(0x5d); ASM((argn - 4) * sizeof(PN));
408  X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x5d,regn) // mov %rbp(A) %rbx
409  }
410  break;
411  }
412 #endif
413 }
414 
415 void potion_x86_setup(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp) {
416  ASM(0x55); // push %rbp
417  X86_PRE(); ASM(0x89); ASM(0xE5); // mov %rsp,%rbp
418 }
419 
420 void potion_x86_stack(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, long need) {
421  /* maintain 16-byte stack alignment. OS X in particular requires it, because
422  * it expects to be able to use movdqa on things on the stack.
423  * we factor in the offset from our saved ebp and return address, so that
424  * adds 8 for x86 and 0 (mod 16) for x86_64. */
425  int rsp = X86C(16,0,0,0)+((need-X86C(8,0,0,0)+15)&~(15));
426  if (rsp >= 0x80) {
427  X86_PRE(); ASM(0x81); ASM(0xEC); ASMI(rsp); // sub rsp, %esp
428  } else {
429  X86_PRE(); ASM(0x83); ASM(0xEC); ASM(rsp); // sub rsp, %esp
430  }
431 }
432 
433 void potion_x86_registers(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, long start) {
434  PN_HAS_UPVALS(up);
435  // (Potion *, self) in the first argument slot, self in the first register
436  // DBG_v(";regs start %ld\n", start);
437  X86_ARGI(start - 3, 0);
438  X86_ARGI(start - 2, 1);
439  X86_ARGI(start - 1, 2);
440  X86_ARGI(0, 2);
441  // empty locals, since use of setlocal requires something there
442  if (up) {
443  int argx = 0, regs = PN_INT(f->stack);
444  for (argx = 0; argx < PN_TUPLE_LEN(f->locals); argx++) {
445  X86_MOVQ(regs + argx, PN_NIL);
446  }
447  }
448 }
449 
450 void potion_x86_local(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, long reg, long arg) {
451  X86_ARGI(reg, 3 + arg);
452 }
453 
454 void potion_x86_upvals(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, long lregs, long start, int upc) {
455  int upi;
456  for (upi = 0; upi < upc; upi++) {
457  int n = sizeof(struct PNClosure) + ((upi + 1) * sizeof(PN));
458  X86_MOV_RBP(0x8B, start - 2); // mov -0x8(%ebp), %eax
459  X86_PRE(); ASM(0x8B); // mov n(%eax), %eax
460  if (n >= 0x80) { ASM(0x80); ASMI(n); } // if more than ~15 upvals
461  else { ASM(0x40); ASM(n); }
462  X86_MOV_RBP(0x89, lregs + upi); // mov %eax, -0x8(%ebp)
463  }
464 }
465 
466 void potion_x86_jmpedit(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, unsigned char *asmj, int dist) {
467  *((int *)asmj) = dist;
468 }
469 
470 void potion_x86_move(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
471  PN_OP op = PN_OP_AT(f->asmb, pos);
472  X86_MOV_RBP(0x8B, op.b);
473  X86_MOV_RBP(0x89, op.a);
474 }
475 
476 void potion_x86_loadpn(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
477  PN_OP op = PN_OP_AT(f->asmb, pos);
478  X86_MOVQ(op.a, op.b);
479 }
480 
482  return potion_fwd(PN_PROTO(PN_CLOSURE(cl)->data[0])->values);
483 }
484 
485 void potion_x86_loadk(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
486  PN_OP op = PN_OP_AT(f->asmb, pos);
487  X86_ARGO(start - 3, 0);
488  X86_ARGO(start - 2, 1);
489  X86_PRE(); ASM(0xB8); ASMN(potion_f_values); // mov &potion_f_values %rax
490  ASM(0xFF); ASM(0xD0); // callq %rax
491  X86_PRE(); ASM(0x05); ASMI(sizeof(struct PNTuple)
492  + (op.b * sizeof(PN))); // add N,%rax
493  X86_PRE(); ASM(0x8B); ASM(0); // mov (%rax) %rax
494  X86_MOV_RBP(0x89, op.a); // mov %eax,-A(%ebp)
495 }
496 
497 void potion_x86_self(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
498  PN_OP op = PN_OP_AT(f->asmb, pos);
499  X86_MOV_RBP(0x8B, start - 1); // mov %rsp(self), %rax
500  X86_MOV_RBP(0x89, op.a); // mov %eax,-A(%ebp)
501 }
502 
503 
504 // reg[op.a] = PN_IS_REF(locals[op.b]) ? PN_DEREF(locals[op.b]) : locals[op.b];
505 void potion_x86_getlocal(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long regs) {
506  PN_OP op = PN_OP_AT(f->asmb, pos);
507  PN_HAS_UPVALS(up);
508  X86_MOV_RBP(0x8B, regs + op.b); // mov %ebp(B) %eax
509  if (up) { // upvals need to be deref'd
510  ASMS("\xF6\xC0\x01" // test 0x1 %al
511  "\x75"); ASM(X86C(19,20, 0,0)); // jnz a
512  ASMS("\xF7\xC0"); ASMI(PN_REF_MASK); // test REFMASK %eax
513  ASM(0x74); ASM(X86C(11,12, 0,0)); // jz a
514  ASMS("\x81\x38"); ASMI(PN_TWEAK); // cmpq WEAK (%eax) # 0x250004
515  ASM(0x75); ASM(X86C(3,4, 0,0)); // jnz a
516  X86_PRE(); ASM(0x8B); ASM(0x40);
517  ASM(sizeof(struct PNObject)); // mov N(%eax) %eax; #WeakRef->data (Obj+PN)
518  }
519  X86_MOV_RBP(0x89, op.a); // a: mov %eax %esp(A)
520 }
521 
522 // if (PN_IS_REF(locals[op.b])) PN_DEREF(locals[op.b]) = reg[op.a];
523 // else locals[op.b] = reg[op.a];
524 void potion_x86_setlocal(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long regs) {
525  PN_OP op = PN_OP_AT(f->asmb, pos);
526  PN_HAS_UPVALS(up);
527  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55, op.a) // mov %rsp(A) %rdx
528  if (up) { // upvals need to be deref'd
529  X86_MOV_RBP(0x8B, regs + op.b); // mov %rsp(B) %rax
530  ASMS("\xF6\xC0\x01" // test 0x1 %al
531  "\x75"); ASM(X86C(19,20, 0,0)); // jnz a
532  ASMS("\xF7\xC0"); ASMI(PN_REF_MASK); // test REFMASK %eax
533  ASM(0x74); ASM(X86C(11,12, 0,0)); // jz a
534  ASMS("\x81\x38"); ASMI(PN_TWEAK); // cmpq WEAK (%rax) # 0x250004
535  ASM(0x75); ASM(X86C(3,4, 0,0)); // jnz a
536  X86_PRE(); ASM(0x89); ASM(0x50);
537  ASM(sizeof(struct PNObject)); // mov N(%rax) %rax
538  }
539  X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x55, regs + op.b)// a: mov %rdx %rsp(B)
540 }
541 
542 // reg[op.a] = PN_DEREF(upvals[op.b])
543 void potion_x86_getupval(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long lregs) {
544  PN_OP op = PN_OP_AT(f->asmb, pos);
545  X86_MOV_RBP(0x8B, lregs + op.b);
546  X86_PRE(); ASM(0x8B); ASM(0x40); ASM(sizeof(struct PNObject));
547  X86_MOV_RBP(0x89, op.a);
548 }
549 
550 // PN_DEREF(upvals[op.b]) = reg[op.a]
551 // TODO: place the upval in the write barrier (or have stack scanning handle weak refs)
552 void potion_x86_setupval(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long lregs) {
553  PN_OP op = PN_OP_AT(f->asmb, pos);
554  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55, op.a) // mov -A(%rbp) %edx
555  X86_MOV_RBP(0x8B, lregs + op.b); // mov %rsp(B) %rax
556  X86_PRE(); ASM(0x89); ASM(0x50); ASM(sizeof(struct PNObject));// mov %rdx %rax.data
557 }
558 
559 void potion_x86_global(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
560  PN_OP op = PN_OP_AT(f->asmb, pos);
561  X86_ARGO(start - 3, 0);
562  X86_ARGO(op.a, 1);
563  X86_ARGO(op.b, 2);
564  X86_PRE(); ASM(0xB8); ASMN(potion_define_global); // mov &potion_define_global, %rax
565  ASM(0xFF); ASM(0xD0); // callq %rax
566  X86_MOV_RBP(0x8B, op.b); // mov -B(%rbp) %eax
567  X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x45, op.a) // mov %eax -A(%rbp)
568 }
569 
570 void potion_x86_newtuple(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
571  PN_OP op = PN_OP_AT(f->asmb, pos);
572  X86_ARGO(start - 3, 0);
573  X86_PRE(); ASM(0xB8); ASMN(potion_tuple_empty);// mov &potion_tuple_empty %rax
574  ASM(0xFF); ASM(0xD0); // callq %rax
575  X86_MOV_RBP(0x89, op.a); // mov %rax local
576 }
577 
578 // the fast version for unsafe unchecked direct access to the PNTuple offset
579 // with immediate constant directly, and the indirect version uses R(B-1024)
580 void potion_x86_gettuple(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
581  PN_OP op = PN_OP_AT(f->asmb, pos);
582  X86_ARGO(op.a, 0); // movq -A(%rbp), %rdi
583  X86_PRE(); ASM(0xB8); ASMN(potion_fwd); // mov &potion_fwd, %rax
584  ASM(0xFF); ASM(0xD0); // callq %rax
585  if (op.b & ASM_TPL_IMM) { // not immediate index. R(B-1024)
586  X86_PRE();ASM(0x8b);ASM_MOV_EBP(0x55,op.b-ASM_TPL_IMM); // mov -B-1024(%rbp) %rdx
587  X86_PRE();ASMS("\xd1\xea"); // shr %rdx,1
588  //ASM(0xcc); // displacement: 0x90 or 0xd0
589  X86_PRE();ASM(0x8b);ASM(0x44);ASM((5+PN_SIZE_T)<<4);ASM(0x10);// mov 0x10(%rax,%rdx,PN_SIZE_T),%rax
590  } else { // immediate index B
591  X86_PRE();ASM(0xc7);ASM(0xc2);ASMI(op.b+2); // mov B+$2, %rdx #PNTuple+2
592  X86_PRE();ASM(0x8b);ASM(0x04);ASM((5+PN_SIZE_T)<<4);// mov (%rax,%rdx,PN_SIZE_T),%rax
593  }
594  X86_MOV_RBP(0x89, op.a); // mov %rax local
595  return;
596 }
597 
598 void potion_x86_settuple(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
599  PN_OP op = PN_OP_AT(f->asmb, pos);
600  X86_ARGO(start - 3, 0);
601  X86_ARGO(op.a, 1);
602  X86_ARGO(op.b, 2);
603  X86_PRE(); ASM(0xB8); ASMN(potion_tuple_push);// mov &potion_tuple_push %rax
604  ASM(0xFF); ASM(0xD0); // callq %rax
605  X86_MOV_RBP(0x89, op.a); // mov %rax local
606 }
607 
608 void potion_x86_gettable(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
609  PN_OP op = PN_OP_AT(f->asmb, pos);
610  X86_ARGO(start - 3, 0);
611  //X86_ARGO(0, 1);
612  X86_ARGO(op.a, 2);
613  X86_ARGO(op.b, 3);
614  X86_PRE(); ASM(0xB8); ASMN(potion_table_at); // mov &potion_table_set %rax
615  ASM(0xFF); ASM(0xD0); // callq %rax
616  X86_MOV_RBP(0x89, op.a); // mov %rax local
617 }
618 
619 void potion_x86_settable(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
620  PN_OP op = PN_OP_AT(f->asmb, pos);
621  X86_ARGO(start - 3, 0);
622  X86_ARGO(op.a, 1);
623  X86_ARGO(op.a + 1, 2);
624  X86_ARGO(op.b, 3);
625  X86_PRE(); ASM(0xB8); ASMN(potion_table_set); // mov &potion_table_set %rax
626  ASM(0xFF); ASM(0xD0); // callq %rax
627  X86_MOV_RBP(0x89, op.a); // mov %rax local
628 }
629 
630 void potion_x86_newlick(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
631  int nnil = 0;
632  PN_OP op = PN_OP_AT(f->asmb, pos);
633  X86_ARGO(start - 3, 0);
634  X86_ARGO(op.a, 1);
635  if (op.b > op.a) {
636  X86_ARGO(op.a + 1, 2);
637  } else {
638  nnil = 1;
639  X86_MOVQ(op.a, PN_NIL);
640  X86_ARGO(op.a, 2);
641  }
642  if (op.b > op.a + 1) {
643  X86_ARGO(op.b, 3);
644  } else {
645  if (!nnil) { X86_MOVQ(op.a, PN_NIL); }
646  X86_ARGO(op.a, 3);
647  }
648  X86_PRE(); ASM(0xB8); ASMN(potion_lick); // mov &potion_lick %rax
649  ASM(0xFF); ASM(0xD0); // callq %rax
650  X86_MOV_RBP(0x89, op.a); // mov %rax local
651 }
652 
653 void potion_x86_getpath(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
654  PN_OP op = PN_OP_AT(f->asmb, pos);
655  X86_ARGO(start - 3, 0);
656  X86_ARGO(op.a, 2);
657  X86_ARGO(op.b, 3);
658  X86_PRE(); ASM(0xB8); ASMN(potion_obj_get); // mov &potion_obj_get %rax
659  ASM(0xFF); ASM(0xD0); // callq %rax
660  X86_MOV_RBP(0x89, op.a); // mov %rax local
661 }
662 
663 void potion_x86_setpath(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
664  PN_OP op = PN_OP_AT(f->asmb, pos);
665  X86_ARGO(start - 3, 0);
666  X86_ARGO(op.a, 2);
667  X86_ARGO(op.a + 1, 3);
668  X86_ARGO(op.b, 4);
669  X86_PRE(); ASM(0xB8); ASMN(potion_obj_set); // mov &potion_obj_set %rax
670  ASM(0xFF); ASM(0xD0); // callq %rax
671 }
672 
673 void potion_x86_add(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
674  PN_OP op = PN_OP_AT(f->asmb, pos);
676  X86_PRE(); ASMS("\x8D\x44\x10\xFF"); // lea -1(%eax,%edx,1),%eax
677  ASM(0x70); ASM(2); // jo +2
678  });
679 }
680 
681 void potion_x86_sub(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
682  PN_OP op = PN_OP_AT(f->asmb, pos);
684  X86_PRE(); ASM(0x29); ASM(0xD0); // sub %edx %eax
685  ASM(0x70); ASM(X86_PRE_T + 4); // jo +4
686  X86_PRE(); ASM(0xFF); ASM(0xC0); // inc %eax
687  });
688 }
689 
690 void potion_x86_mult(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
691  PN_OP op = PN_OP_AT(f->asmb, pos);
693  X86_PRE(); ASMS("\xD1\xFA"); // sar %rdx
694  X86_PRE(); ASMS("\xFF\xC8"); // dec %rax
695  X86_PRE(); ASMS("\x0F\xAF\xC2"); // imul %rdx %rax
696  ASM(0x70); ASM(X86_PRE_T + 4); // jo +4
697  X86_PRE(); ASMS("\xFF\xC0"); // inc %rax
698  });
699 }
700 
701 void potion_x86_div(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
702  PN_OP op = PN_OP_AT(f->asmb, pos);
704  ASMS("\xD1\xF8" // sar %rax
705  "\xD1\xFA" // sar %edx
706  "\x89\xD1" // mov %edx %ecx
707  "\x89\xC2" // mov %eax %edx
708  "\xC1\xFA\x1F" // sar 0x1f %edx
709  "\xF7\xF9" // idiv %ecx
710  "\x8D\x44\x00\x01"); // lea 0x1(%eax,%eax,1),%eax
711  });
712 }
713 
714 void potion_x86_rem(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
715  PN_OP op = PN_OP_AT(f->asmb, pos);
717  ASMS("\xD1\xF8" // sar %rax
718  "\xD1\xFA" // sar %edx
719  "\x89\xD1" // mov %edx %ecx
720  "\x89\xC2" // mov %eax %edx
721  "\xC1\xFA\x1F" // sar 0x1f %edx
722  "\xF7\xF9" // idiv %ecx
723  "\x8D\x44\x12\x01"); // lea 0x1(%edx,%edx,1),%eax
724  });
725 }
726 
727 void potion_x86_pow(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
728  PN_OP op = PN_OP_AT(f->asmb, pos);
729  X86_ARGO(start - 3, 0);
730  X86_ARGO(op.a, 2);
731  X86_ARGO(op.b, 3);
732  X86_PRE(); ASM(0xB8); ASMN(potion_num_pow);// mov &potion_num_pow %rax
733  ASM(0xFF); ASM(0xD0); // callq %rax
734  X86_MOV_RBP(0x89, op.a); // mov %rax local
735 }
736 
737 void potion_x86_neq(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
738  PN_OP op = PN_OP_AT(f->asmb, pos);
739  X86_ARGO(start - 3, 0); // mov &P 0(%esp)
740  X86_ARGO(op.a, 1); // mov A 1(%esp)
741  X86_ARGO(op.b, 2); // mov B 2(%esp)
742  X86_PRE(); ASM(0xB8); ASMN(potion_vm_neq); // mov &potion_vm_neq %rax
743  ASM(0xFF); ASM(0xD0); // callq %rax
744  X86_MOV_RBP(0x89, op.a); // mov %rax local
745  //x86_cmp(P, asmp, op, 0x75, 0x74); // jne
746  //X86_CMP(0x75, 0x85); // jne
747 }
748 
749 void potion_x86_eq(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
750  PN_OP op = PN_OP_AT(f->asmb, pos);
751  X86_ARGO(start - 3, 0); // mov &P 0(%esp)
752  X86_ARGO(op.a, 1); // mov A 1(%esp)
753  X86_ARGO(op.b, 2); // mov B 2(%esp)
754  X86_PRE(); ASM(0xB8); ASMN(potion_vm_eq); // mov &potion_vm_eq %rax
755  ASM(0xFF); ASM(0xD0); // callq %rax
756  X86_MOV_RBP(0x89, op.a); // mov %rax local
757  //x86_cmp(P, asmp, op, 0x74, 0x75); // je
758  //X86_CMP(0x74, 0x84); // je
759 }
760 
761 void potion_x86_lt(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
762  PN_OP op = PN_OP_AT(f->asmb, pos);
763  X86_NUMCMP(0x7C, 0x72, // jl, jb
764  "\x66\x0F\x2e\xc1" // ucomisd %xmm1, %xmm0
765  );
766 }
767 
768 void potion_x86_lte(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
769  PN_OP op = PN_OP_AT(f->asmb, pos);
770  X86_NUMCMP(0x7E, 0x76, // jle, jbe
771  "\x66\x0F\x2e\xc1" // ucomisd %xmm1, %xmm0
772  );
773 }
774 
775 void potion_x86_gt(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
776  PN_OP op = PN_OP_AT(f->asmb, pos);
777  X86_NUMCMP(0x7F, 0x77, // jg, ja
778  "\x66\x0F\x2e\xc1" // ucomisd %xmm1, %xmm0
779  );
780 }
781 
782 void potion_x86_gte(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
783  PN_OP op = PN_OP_AT(f->asmb, pos);
784  X86_NUMCMP(0x7D, 0x73, // jge, jae
785  "\x66\x0F\x2e\xc1" // ucomisd %xmm1, %xmm0
786  );
787 }
788 
789 void potion_x86_bitn(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
790  PN_OP op = PN_OP_AT(f->asmb, pos);
792  X86_PRE(); ASM(0xF7); ASM(0xD0); // not %eax
793  X86_PRE(); ASM(0xFF); ASM(0xC0); // inc %rax
794  });
795 }
796 
797 void potion_x86_bitl(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
798  PN_OP op = PN_OP_AT(f->asmb, pos);
800  ASMS("\xD1\xF8" // sar %eax
801  "\xD1\xFA" // sar %edx
802  "\x89\xD1" // mov %edx %ecx
803  "\x89\xC2" // mov %eax %edx
804  "\xD3\xE0"); // sal %cl %eax
805  ASM(0x70); ASM(6); // jo +6
806  ASMS("\x8D\x44\x00\x01"); // lea 0x1(%eax,%eax,1),%eax
807  });
808 }
809 
810 void potion_x86_bitr(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
811  PN_OP op = PN_OP_AT(f->asmb, pos);
813  ASMS("\xD1\xF8" // sar %rax
814  "\xD1\xFA" // sar %edx
815  "\x89\xD1" // mov %edx %ecx
816  "\x89\xC2" // mov %eax %edx
817  "\xD3\xF8"); // sar %cl %eax
818  ASM(0x70); ASM(6); // jo +6
819  ASMS("\x8D\x44\x00\x01"); // lea 0x1(%eax,%eax,1),%eax
820  });
821 }
822 
823 void potion_x86_def(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
824  PN_OP op = PN_OP_AT(f->asmb, pos);
825  X86_ARGO(start - 3, 0);
826  X86_ARGO(op.a, 2);
827  X86_ARGO(op.a + 1, 3);
828  X86_ARGO(op.b, 4);
829  X86_PRE(); ASM(0xB8); ASMN(potion_def_method); // mov &potion_def_method %rax
830  ASM(0xFF); ASM(0xD0); // callq %rax
831  X86_MOV_RBP(0x89, op.a); // mov %rax local
832 }
833 
834 void potion_x86_bind(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
835  PN_OP op = PN_OP_AT(f->asmb, pos);
836  X86_ARGO(start - 3, 0); // mov &P 0(%esp) (0, 3)
837  X86_ARGO(op.b, 1); // mov B 1(%esp) - new env (7, 3)
838  X86_ARGO(op.a, 2); // mov A 2(%esp) (7, 3)
839  X86_PRE(); ASM(0xB8); ASMN(potion_bind); // mov &potion_bind %rax
840  ASM(0xFF); ASM(0xD0); // callq %rax
841  X86_MOV_RBP(0x89, op.a); // mov %rax local
842 }
843 
844 void potion_x86_message(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
845  PN_OP op = PN_OP_AT(f->asmb, pos);
846  X86_ARGO(start - 3, 0); // mov &P 0(%esp) (0, 3)
847  X86_ARGO(op.b, 1); // mov B 1(%esp) - new env (7, 3)
848  X86_ARGO(op.a, 2); // mov A 2(%esp) (7, 3)
849  X86_PRE(); ASM(0xB8); ASMN(potion_message); // mov &potion_message %rax
850  ASM(0xFF); ASM(0xD0); // callq %rax
851  X86_MOV_RBP(0x89, op.a); // mov %rax local
852 }
853 
854 void potion_x86_jmp(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc) {
855  PN_OP op = PN_OP_AT(f->asmb, pos);
856  TAG_JMP(pos + op.a);
857 }
858 
859 void potion_x86_test_asm(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, int test) {
860  int false1, false2, true1;
861 #ifdef P2
862  int false3, false4;
863 #endif
864  PN_OP op = PN_OP_AT(f->asmb, pos);
865  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
866  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_FALSE); // cmp %eax, $2 (FALSE)
867 #ifdef P2
868  TAG_PREP(false1); ASM(0x74); ASM(0); // je false
869  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_ZERO); // cmp %rax, $1 (ZERO)
870  TAG_PREP(false3); ASM(0x74); ASM(0); // je false
871 #if PN_SIZE_T != 8
872  ASM(0x3d); ASMN(PN_STR0); // cmp %eax, $PN_STR0
873  TAG_PREP(false4); ASM(0x74); ASM(0); // jz false (+13,21)
874 #else
875  X86_PRE(); ASM(0xb8); ASMN(PN_STR0); // mov $PN_STR0, %rax
876  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax
877  TAG_PREP(false4); ASM(0x74); ASM(0); // jz false
878  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
879 #endif
880 #else
881  TAG_PREP(false1); ASM(0x74); ASM(0); // jz false (+13,21)
882 #endif
883  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax (NIL)
884  TAG_PREP(false2); ASM(0x74); ASM(0); // jz false (+9,16)
885  X86_MOVQ(op.a, test ? PN_FALSE : PN_TRUE); // -A(%rbp) = TRUE
886  TAG_PREP(true1); ASM(0xEB); ASM(0); // jmp true (+7,14)
887  TAG_LABEL(false1); TAG_LABEL(false2); //false:
888 #ifdef P2
889  TAG_LABEL(false3); TAG_LABEL(false4);
890 #endif
891  X86_MOVQ(op.a, test ? PN_TRUE : PN_FALSE); // -A(%rbp) = FALSE
892  TAG_LABEL(true1); //true:
893 }
894 
895 void potion_x86_test(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
896  potion_x86_test_asm(P, f, asmp, pos, 0);
897 }
898 
899 void potion_x86_not(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
900  potion_x86_test_asm(P, f, asmp, pos, 1);
901 }
902 
903 void potion_x86_cmp(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
904  potion_x86_test_asm(P, f, asmp, pos, 0);
905 }
906 
907 void potion_x86_testjmp(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc) {
908  PN_OP op = PN_OP_AT(f->asmb, pos);
909  int false1;
910 #ifdef P2
911  int false2, false3;
912 #endif
913  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
914  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_FALSE); // cmp FALSE %rax
915  TAG_PREP(false1); ASM(0x74); ASM(0); // jz false
916 #ifdef P2
917  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_ZERO); // cmp %rax, $1 (ZERO)
918  TAG_PREP(false2); ASM(0x74); ASM(0); // jz false
919 #if PN_SIZE_T != 8
920  ASM(0x3d); ASMN(PN_STR0); // cmp %eax, $PN_STR0
921  TAG_PREP(false3); ASM(0x74); ASM(0); // je false
922 #else
923  X86_PRE(); ASM(0xb8); ASMN(PN_STR0); // mov $PN_STR0, %rax
924  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax
925  TAG_PREP(false3); ASM(0x74); ASM(0); // jz false
926  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
927 #endif
928 #endif
929  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax (NIL)
930  ASM(0x74); ASM(5); // jz false
931  TAG_JMP(pos + op.b); //true:
932  TAG_LABEL(false1);
933 #ifdef P2
934  TAG_LABEL(false2); TAG_LABEL(false3);
935 #endif
936 }
937 
938 void potion_x86_notjmp(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc) {
939  PN_OP op = PN_OP_AT(f->asmb, pos);
940  int false1;
941 #ifdef P2
942  int false2, false3;
943 #endif
944  DBG_t("; notjmp %d => %d\n", op.a, op.b);
945  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
946  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_FALSE); // cmp FALSE %rax
947  TAG_PREP(false1); ASM(0x74); ASM(0); // jz false
948 #ifdef P2
949  X86_PRE(); ASM(0x83); ASM(0xF8); ASM(PN_ZERO); // cmp %rax, $1 (ZERO)
950  TAG_PREP(false2); ASM(0x74); ASM(0); // jz false
951 #if PN_SIZE_T != 8
952  ASM(0x3d); ASMN(PN_STR0); // cmp %eax, $PN_STR0
953  TAG_PREP(false3); ASM(0x74); ASM(0); // je false (+13,21)
954 #else
955  X86_PRE(); ASM(0xb8); ASMN(PN_STR0); // mov $PN_STR0, %rax
956  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax
957  TAG_PREP(false3); ASM(0x74); ASM(0); // jz false
958  X86_MOV_RBP(0x8B, op.a); // mov -A(%rbp) %rax
959 #endif
960 #endif
961  X86_PRE(); ASM(0x85); ASM(0xC0); // test %rax %rax (NIL)
962  ASM(0x75); ASM(5); // jnz true (+5)
963  TAG_LABEL(false1);
964 #ifdef P2
965  TAG_LABEL(false2);TAG_LABEL(false3); //false:
966 #endif
967  TAG_JMP(pos + op.b);
968 } // true:
969 
970 void potion_x86_named(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
971  int tag;
972  PN_OP op = PN_OP_AT(f->asmb, pos);
973  DBG_t("; named %d %d\n", op.a, op.b);
974  X86_ARGO(start - 3, 0); //P
975  X86_ARGO(op.a, 1); //cl
976  X86_ARGO(op.b - 1, 2); //name
977  X86_PRE(); ASM(0xB8); ASMN(potion_sig_find); // mov &potion_sig_find %rax
978  ASMS("\xFF\xD0" // callq %eax
979  "\x85\xC0"); // test %eax %eax
980  TAG_PREP(tag);
981  ASM(0x78); ASM(0); // js +12
982  X86_PRE(); ASM(0xF7); ASM(0xD8); // neg %rax
983  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55, op.b) // mov -B(%rbp) %rdx
984 #if PN_SIZE_T != 8
985  ASM(0x89); ASM(0x54); ASM_MOV_EBP(0x85, op.a + 2) // mov %edx -A(%ebp,%eax,4)
986 #else
987  if (op.a + 2 > 15) {
988  DBG_v("named: mov %%rdx -A=%d(%%rbp,%%rax,8)\n", op.a + 2);
989  X86_PRE(); ASM(0x89); ASM(0x94); ASM(0xC5); ASM(RBP(op.a + 2)); ASM(0xff); ASM(0xff);
990  } else {
991  X86_PRE(); ASM(0x89); ASM(0x54); ASM(0xC5); ASM(RBP(op.a + 2)); // mov %rdx -A(%rbp,%rax,8)
992  }
993 #endif
994  TAG_LABEL(tag);
995 }
996 
997 // TODO: check for bytecode nodes and jit them as well?
998 void potion_x86_call(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
999  PN_OP op = PN_OP_AT(f->asmb, pos);
1000  int argc = op.b - op.a; // including self
1001  int i, tag_a1, tag_a2, tag_b, tag_c, tag_d;
1002 
1003  // check type of the closure
1004  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x45, op.a) // mov %rbp(A) %rax
1005  ASM(0xF6); ASM(0xC0); ASM(0x01); // test 0x1 %al
1006  TAG_PREP(tag_a1);
1007  ASM(0x75); ASM(X86C(56,68, 3,op.a)); // jnz [a]
1008  ASM(0xF7); ASM(0xC0); ASMI(PN_REF_MASK); // test REFMASK %eax
1009  TAG_PREP(tag_a2);
1010  ASM(0x74); ASM(X86C(48,60, 5,op.a)); // jz [a]
1011  X86_PRE(); ASM(0x83); ASM(0xE0); ASM(0xF8); // and ~PRIMITIVE %rax
1012 
1013  // if a class, pull out the constructor
1014  ASM(0x81); ASM(0x38); ASMI(PN_TVTABLE); // cmpq VTABLE (%eax) # 0x25000a
1015  TAG_PREP(tag_c);
1016  ASM(0x75); ASM(X86C(13,20, 1, start-3)); // jnz [c]
1017  X86_ARGO(start - 3, 0); // mov &P 0(%esp)
1018  X86_ARGO(op.a, 2); // mov A 2(%esp)
1019  X86_PRE(); ASM(0xB8); ASMN(potion_object_new); // mov &potion_object_new %rax
1020  ASM(0xFF); ASM(0xD0); // callq %rax
1021  X86_MOV_RBP(0x89, op.a + 1); // mov %rax local
1022  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x45, op.a) // mov %rbp(A) %rax
1023  X86_PRE(); ASM(0x8B); ASM(0x40);
1024  ASM((char *)&((struct PNVtable *)P->lobby)->ctor
1025  - (char *)P->lobby); // mov N(%rax) %rax
1026  X86_PRE(); ASM(0x89); ASM_MOV_EBP(0x45, op.a) // mov %rax %rbp(A)
1027 
1028  // check type of the closure
1029  TAG_LABEL(tag_c);
1030  ASM(0x81); ASM(0x38); ASMI(PN_TCLOSURE); // c: cmpq CLOSURE (%eax) # 0x250005
1031  TAG_PREP(tag_d);
1032  ASM(0x74); ASM(X86C(22,30, 2,op.a)); // jz [d]
1033 
1034  // if not a closure, get the type's closure
1035  X86_MOV_RBP(0x8B, op.a);
1036  TAG_LABEL(tag_a1); TAG_LABEL(tag_a2);
1037  X86_MOV_RBP(0x89, op.a + 1);
1038  X86_ARGO(start - 3, 0); // a: mov &P 0(%esp)
1039  X86_ARGO(op.a, 1); // mov A 1(%esp)
1040  X86_PRE(); ASM(0xB8); ASMN(potion_obj_get_call); // mov &potion_obj_get_call %rax
1041  ASM(0xFF); ASM(0xD0); // callq *%rax
1042  TAG_PREP(tag_b);
1043  ASM(0xEB); ASM(X86C(3,4, 1,op.a)); // jmp [b]
1044 
1045  // get the closure's function
1046  TAG_LABEL(tag_d);
1047  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x45, op.a) // d: mov %rbp(A) %rax
1048  //[b]: got the method, call it (first special slot from PNClosure)
1049  TAG_LABEL(tag_b);
1050  X86_PRE(); ASM(0x8B); ASM(0x40);
1051  ASM(sizeof(struct PNObject)); // b: mov N(%rax) %rax
1052 
1053  // (Potion *, CL) as the first arguments
1054  X86_ARGO(start - 3, 0);
1055  X86_ARGO(op.a, 1);
1056  DBG_t("; call %ld[0] %d[1] ", start-3, op.a);
1057  for (i=2; i <= argc+1; i++) {
1058  DBG_t("%d[%d] ", op.a + i - 1, i);
1059  X86_ARGO(op.a + i - 1, i); // mov regn, i(%esp)
1060  }
1061  // fill in defaults, arity from protos[0], not f
1062  if (!PN_IS_EMPTY(f->protos)) {
1063  vPN(Proto) c = (vPN(Proto)) PN_TUPLE_AT(f->protos, 0);
1064  int arity = c->arity;
1065  if (arity && (argc-1 < arity)) {
1066  for (i = argc+1; i <= arity+1; i++) { //2: [0,1],2,3
1067  PN sig = potion_sig_at(P, c->sig, i-2);
1068  if (sig && PN_TUPLE_LEN(sig) == 3) {
1069  DBG_t(":=*%s[%d] ", AS_STR(PN_TUPLE_AT(sig, 2)), i+1);
1070  X86_ARGO_IMM(PN_TUPLE_AT(sig, 2), i+1); // mov $value, i(%esp) - default
1071  } else if (sig) {
1072  DBG_t("|0 "); // mov 0, i(%esp) - optional
1073  char type = (char)(PN_TUPLE_LEN(sig) > 1
1074  ? PN_INT(PN_TUPLE_AT(sig,1)) : 0);
1075  X86_ARGO_IMM(type ? potion_type_default(type) : 0, i+1);
1076  }}}}
1077  DBG_t("\n");
1078  ASM(0xFF); ASM(0xD0); // callq *%rax
1079  X86_PRE(); ASM(0x89); ASM(0x45); ASM(RBP(op.a)); // mov %rbp(A) %rax
1080 }
1081 
1082 void potion_x86_callset(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
1083  PN_OP op = PN_OP_AT(f->asmb, pos);
1084  X86_ARGO(start - 3, 0);
1085  X86_ARGO(op.b, 1);
1086  X86_PRE(); ASM(0xB8); ASMN(potion_obj_get_callset); // mov &potion_obj_get %rax
1087  ASM(0xFF); ASM(0xD0); // callq %rax
1088  X86_MOV_RBP(0x89, op.a); // mov %rax local
1089 }
1090 
1091 /*TODO*/
1092 void potion_x86_tailcall(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
1093 }
1094 
1095 void potion_x86_return(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos) {
1096  X86_MOV_RBP(0x8B, 0); // mov -0(%rbp) %eax
1097  ASM(0xC9); ASM(0xC3); // leave; ret
1098 }
1099 
1101  PN p = PN_PROTO(PN_CLOSURE(cl)->data[0])->protos;
1102  PN proto = PN_TUPLE_AT(p, i);
1103  vPN(Closure) c = (struct PNClosure *)potion_closure_new(P, NULL,
1104  PN_PROTO(proto)->sig, PN_TUPLE_LEN(PN_PROTO(proto)->upvals) + 1);
1105  c->method = PN_PROTO(proto)->jit;
1106  c->data[0] = proto;
1107  return (PN)c;
1108 }
1109 
1110 /* OP_PROTO */
1111 void potion_x86_method(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE *pos, long lregs, long start, long regs) {
1112  PN_OP op = PN_OP_AT(f->asmb, *pos);
1113  PN proto = PN_TUPLE_AT(f->protos, op.b);
1114  X86_ARGO(start - 3, 0);
1115  X86_ARGO(start - 2, 1);
1116  X86_MOVQ(op.a, op.b);
1117  X86_ARGO(op.a, 2);
1118  X86_PRE(); ASM(0xB8); ASMN(potion_f_protos); // mov &potion_f_values %rax
1119  ASM(0xFF); ASM(0xD0); // callq %rax
1120  X86_MOV_RBP(0x89, op.a);
1121  X86_MOVQ(start - 3, P);
1122  PN_TUPLE_COUNT(PN_PROTO(proto)->upvals, i, {
1123  int n;
1124  (*pos)++;
1125  PN_OP opp = PN_OP_AT(f->asmb, *pos);
1126  if (opp.code == OP_GETUPVAL) {
1127  X86_PRE(); ASM(0x8B); ASM_MOV_EBP(0x55, lregs + opp.b) // mov upval %rdx
1128  } else if (opp.code == OP_GETLOCAL) {
1129  X86_ARGO(start - 3, 0);
1130  X86_ARGO(regs + opp.b, 1);
1131  X86_PRE(); ASM(0xB8); ASMN(potion_ref); // mov &potion_ref %rax
1132  ASM(0xFF); ASM(0xD0); // callq %rax
1133  X86_PRE(); ASM(0x89); ASM(0xC2); // mov %rax %rdx
1134  X86_MOV_RBP(0x89, regs + opp.b); // mov %rax local
1135  } else {
1136  fprintf(stderr, "** missing an upval to proto %p\n", (void *)proto);
1137  }
1138  X86_MOV_RBP(0x8B, opp.a); // mov cl %rax
1139  X86_PRE(); ASM(0x89); // mov %rdx N(%rax)
1140  n = sizeof(struct PNClosure) + (sizeof(PN) * (i + 1));
1141  if (n >= 0x80) { ASM(0x90); ASMI(n); }
1142  else { ASM(0x50); ASM(n); }
1143  });
1144 }
1145 
1146 void potion_x86_class(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp, PN_SIZE pos, long start) {
1147  PN_OP op = PN_OP_AT(f->asmb, pos);
1148  X86_ARGO(start - 3, 0);
1149  X86_ARGO(op.b, 1);
1150  X86_ARGO(op.a, 2);
1151  X86_PRE(); ASM(0xB8); ASMN(potion_vm_class); // mov &potion_vm_class %rax
1152  ASM(0xFF); ASM(0xD0); // callq %rax
1153  X86_MOV_RBP(0x89, op.a); // mov %rax local
1154 }
1155 
1156 void potion_x86_finish(Potion *P, struct PNProto * volatile f, PNAsm * volatile *asmp) {
1157 }
1158 
1159 void potion_x86_mcache(Potion *P, vPN(Vtable) vt, PNAsm * volatile *asmp) {
1160  unsigned k;
1161 #if PN_SIZE_T != 8
1162  ASMS("\x55" // push %ebp
1163  "\x89\xE5" // mov %esp %ebp
1164  "\x8B\x55\x08"); // mov 0x8(%ebp) %edx
1165 #endif
1166  for (k = kh_end(vt->methods); k > kh_begin(vt->methods); k--) {
1167  if (kh_exist(PN, vt->methods, k - 1)) {
1168  ASM(0x81); ASM(X86C(0xFA,0xFF, 0,0));
1169  ASMI(PN_UNIQ(kh_key(PN, vt->methods, k - 1))); // cmp NAME %edi
1170  ASM(0x75); ASM(X86C(7,11, 0,0)); // jnz +11
1171  X86_PRE(); ASM(0xB8); ASMN(kh_val(PN, vt->methods, k - 1)); // mov CL %rax
1172 #if PN_SIZE_T != 8
1173  ASM(0x5D);
1174 #endif
1175  ASM(0xC3); // retq
1176  }
1177  }
1178  ASM(0xB8); ASMI(0); // mov NIL %eax
1179 #if PN_SIZE_T != 8
1180  ASM(0x5D);
1181 #endif
1182  ASM(0xC3); // retq
1183 }
1184 
1185 void potion_x86_ivars(Potion *P, PN ivars, PNAsm * volatile *asmp) {
1186 #if PN_SIZE_T != 8
1187  ASMS("\x55" // push %ebp
1188  "\x89\xE5" // mov %esp %ebp
1189  "\x8B\x55\x08"); // mov 0x8(%ebp) %edx
1190 #else
1191 #endif
1192 #if PN_SIZE_T != 8
1193  PN_TUPLE_EACH(ivars, i, v, {
1194  ASM(0x81); ASM(X86C(0xFA,0xFF, 0,0));
1195  ASMI(PN_UNIQ(v)); // cmp UNIQ %edi
1196  ASM(0x75); ASM(X86C(7,6, 0,0)); // jnz +7
1197  ASM(0xB8); ASMI(i); // mov i %rax
1198  ASM(0x5D); // pop %rbp
1199  ASM(0xC3); // retq
1200  });
1201 #else
1202  PN_TUPLE_EACH(ivars, i, v, {
1203  ASM(0x81); ASM(X86C(0xFA,0xFF, 0,0));
1204  ASMI(PN_UNIQ(v)); // cmp UNIQ %edi
1205  ASM(0x75); ASM(X86C(7,6, 0,0)); // jnz +7
1206  ASM(0xB8); ASMI(i); // mov i %rax
1207  ASM(0xC3); // retq
1208  });
1209 #endif
1210  X86_PRE(); ASM(0xB8); ASMN(-1); // mov -1 %rax
1211 #if PN_SIZE_T != 8
1212  ASM(0x5D); // pop %rbp
1213 #endif
1214  ASM(0xC3); // retq
1215 }
1216 
1217 MAKE_TARGET(x86);
#define PN_TUPLE_AT(t, n)
Definition: potion.h:278
void potion_x86_debug()
Definition: vm-x86.c:272
#define RBP(x)
Definition: vm-x86.c:17
PN asmb
assembled instructions
Definition: potion.h:467
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
Definition: objmodel.c:17
#define X86_MOV_RBP(reg, x)
Definition: vm-x86.c:55
void potion_x86_bitr(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:810
PN potion_def_method(Potion *P, PN closure, PN self, PN key, PN method)
define a method for a class
Definition: objmodel.c:351
void potion_x86_call(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:998
#define TAG_LABEL(tag)
Definition: vm-x86.c:66
record labels to be patched
Definition: asm.h:20
klib hash table library based on double hashing http://en.wikipedia.org/wiki/Double_hashing ...
a tuple is an array of PNs.
Definition: potion.h:477
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
#define PN_CLOSURE(x)
Definition: potion.h:225
unsigned long _PN
Definition: potion.h:78
#define X86_MOVQ(reg, x)
Definition: vm-x86.c:61
PN potion_bind(Potion *P, PN rcv, PN msg)
find method for given receiver and message (method lookup)
Definition: objmodel.c:408
a closure is an anonymous function, without closed values,
Definition: potion.h:381
the central vtable, see io http://www.piumarta.com/pepsi/objmodel.pdf
Definition: table.h:24
void potion_x86_setlocal(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long regs)
Definition: vm-x86.c:524
PN potion_obj_set(Potion *P, PN cl, PN self, PN ivar, PN value)
implements OP_SETPATH
Definition: objmodel.c:334
#define TAG_JMPTO(tag)
Definition: vm-x86.c:67
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)
Definition: vm-x86.c:653
static PN potion_type_default(char type)
zero values per type
Definition: potion.h:805
void potion_x86_test_asm(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, int test)
Definition: vm-x86.c:859
void potion_x86_mcache(Potion *P, vPN(Vtable) vt, PNAsm *volatile *asmp)
Definition: vm-x86.c:1159
#define X86_NUMCMP(iop, xop, xmms)
Definition: vm-x86.c:133
void potion_x86_settuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:598
#define PN_TUPLE_LEN(t)
Definition: potion.h:277
void potion_x86_not(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:899
void potion_x86_def(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:823
void potion_x86_newlick(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:630
void potion_x86_local(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long reg, long arg)
Definition: vm-x86.c:450
#define AS_STR(x)
Definition: potion.h:249
void potion_x86_registers(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long start)
Definition: vm-x86.c:433
void potion_x86_test(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:895
PN potion_f_protos(Potion *P, PN cl, PN i)
Definition: vm-x86.c:1100
PN potion_ref(Potion *P, PN data)
Definition: objmodel.c:473
void potion_x86_loadk(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:485
void potion_x86_jmpedit(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, unsigned char *asmj, int dist)
Definition: vm-x86.c:466
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
Definition: potion.h:570
PN data[]
PNString.
Definition: potion.h:389
void potion_x86_lt(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:761
void potion_x86_testjmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
Definition: vm-x86.c:907
int arity
cached number of declared args, including optional
Definition: potion.h:385
void potion_x86_setupval(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long lregs)
Definition: vm-x86.c:552
void potion_x86_getlocal(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long regs)
Definition: vm-x86.c:505
#define kh_end(h)
Definition: khash.h:229
Definition: potion.h:586
void potion_x86_move(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:470
PN potion_obj_bitl(Potion *P, PN a, PN b)
Definition: objmodel.c:460
#define DBG_t(...)
Definition: potion.h:262
the Potion VM instruction set (heavily based on Lua's)
#define PN_INT(x)
Definition: potion.h:214
#define PN_ZERO
Definition: potion.h:140
void potion_x86_setup(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp)
Definition: vm-x86.c:415
PN potion_sig_at(Potion *P, PN sig, int index)
Definition: objmodel.c:136
#define X86_ARGI(regn, argn)
Definition: vm-x86.c:252
PN potion_num_pow(Potion *, PN, PN, PN)
#define ASMS(cstr)
Definition: asm.h:102
void potion_x86_div(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:701
unsigned int PN_SIZE
Definition: potion.h:79
standard objects act like C structs the fields are defined by the type and it's a fixed size...
Definition: potion.h:304
void potion_x86_callset(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:1082
#define PN_TVTABLE
Definition: potion.h:119
#define ASM_MOV_EBP(op, reg)
Definition: vm-x86.c:49
PN lobby
root namespace
Definition: potion.h:657
void potion_x86_add(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:673
#define PN_UNIQ(x)
Definition: potion.h:247
#define X86_MATH(two, dbl_func, ops)
Definition: vm-x86.c:104
PN locals
local variables
Definition: potion.h:460
#define kh_begin(h)
Definition: khash.h:228
#define X86_ARGO(regn, argn)
Definition: vm-x86.c:250
void potion_x86_bind(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:834
void potion_x86_sub(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:681
void potion_x86_pow(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:727
PN potion_f_values(Potion *P, PN cl)
Definition: vm-x86.c:481
void potion_x86_tailcall(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:1092
PN potion_obj_get(Potion *P, PN cl, PN self, PN ivar)
implements OP_GETPATH
Definition: objmodel.c:327
void potion_x86_ivars(Potion *P, PN ivars, PNAsm *volatile *asmp)
Definition: vm-x86.c:1185
void potion_x86_bitl(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:797
#define PN_FALSE
Definition: potion.h:141
PN potion_obj_get_callset(Potion *P, PN obj)
get default writer
Definition: objmodel.c:244
void potion_define_global(Potion *P, PN name, PN val)
Definition: objmodel.c:628
PN potion_obj_sub(Potion *P, PN a, PN b)
Definition: objmodel.c:440
PN potion_obj_add(Potion *P, PN a, PN b)
Definition: objmodel.c:436
void potion_x86_bitn(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:789
void potion_x86_self(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:497
#define PN_TWEAK
Definition: potion.h:113
some assembler macros
#define TAG_JMPF(insn, tag)
Definition: vm-x86.c:69
void potion_x86_notjmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
Definition: vm-x86.c:938
static void potion_x86_c_arg(Potion *P, PNAsm *volatile *asmp, int out, int regn, int argn)
mimick c calling convention
Definition: vm-x86.c:324
#define PN_TRUE
Definition: potion.h:142
void potion_x86_mult(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:690
void potion_x86_eq(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:749
PN potion_obj_mult(Potion *P, PN a, PN b)
Definition: objmodel.c:444
void potion_x86_message(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:844
PN potion_obj_get_call(Potion *P, PN obj)
get the default accessor (usually "at")
Definition: objmodel.c:234
PN potion_tuple_push(Potion *, PN, PN)
Definition: table.c:254
a prototype is compiled source code, a closure block (lambda) non-volatile.
Definition: potion.h:454
PN potion_table_at(Potion *P, PN cl, PN self, PN key)
Definition: table.c:70
#define X86_PRE_T
Definition: vm-x86.c:38
#define DBG_v(...)
Definition: potion.h:263
non-API internal parts
#define X86_ARGO_IMM(regn, argn)
Definition: vm-x86.c:251
PN potion_obj_bitr(Potion *P, PN a, PN b)
Definition: objmodel.c:464
void potion_x86_finish(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp)
Definition: vm-x86.c:1156
PN protos
nested closures
Definition: potion.h:463
#define ASM_TPL_IMM
Definition: asm.h:17
void potion_x86_rem(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:714
#define TAG_JMP(jpos)
Definition: vm-x86.c:253
void potion_x86_gt(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:775
void potion_x86_cmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:903
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 ...
Definition: vm.c:203
#define kh_val(name, h, x)
Definition: khash.h:227
void potion_x86_lte(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:768
PN potion_lick(Potion *P, PN name, PN inner, PN attr)
Definition: lick.c:11
void potion_x86_gettable(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:608
void potion_x86_settable(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:619
#define PN_OP_AT(asmb, n)
Definition: opcodes.h:82
void potion_x86_upvals(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long lregs, long start, int upc)
Definition: vm-x86.c:454
#define X86C(op32, op64, n, reg)
Definition: vm-x86.c:41
#define TAG_JMPTOB(tag)
Definition: vm-x86.c:95
int a
< the op. See vm.c http://www.lua.org/doc/jucs05.pdf
Definition: opcodes.h:71
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:653
#define PN_IS_EMPTY(T)
Definition: potion.h:269
PN potion_obj_rem(Potion *P, PN a, PN b)
Definition: objmodel.c:452
PN sig
signature PNTuple
Definition: potion.h:384
#define PN_TYPE(x)
Definition: potion.h:133
#define kh_key(name, h, x)
Definition: khash.h:226
The p2 API.
PN potion_tuple_empty(Potion *)
Definition: table.c:235
void potion_x86_method(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE *pos, long lregs, long start, long regs)
Definition: vm-x86.c:1111
PN potion_vm_neq(Potion *, PN, PN)
Definition: vm.c:427
PN potion_message(Potion *P, PN rcv, PN msg)
Definition: objmodel.c:429
#define TAG_JMPTOW(tag)
Definition: vm-x86.c:78
void potion_x86_neq(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:737
static PNType potion_type(PN obj)
either immediate (NUM,BOOL,NIL) or a fwd
Definition: potion.h:532
#define TAG_JMPB(insn, tag)
Definition: vm-x86.c:84
the central table type, based on core/khash.h
#define ASMN(pn)
Definition: asm.h:101
void potion_x86_loadpn(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:476
#define TAG_PREP(tag)
Definition: vm-x86.c:65
PN potion_obj_bitn(Potion *P, PN a)
Definition: objmodel.c:456
PN stack
size of the stack
Definition: potion.h:458
#define PN_REF_MASK
Definition: potion.h:144
MAKE_TARGET(x86)
#define vPN(t)
Definition: buffile.c:34
volatile _PN PN
Definition: potion.h:81
PN PN_STR0
Definition: internal.c:18
void potion_x86_named(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:970
int b
optional arg, the message
Definition: opcodes.h:73
#define PN_NIL
Definition: potion.h:139
void potion_x86_return(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:1095
void potion_x86_jmp(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, PNJumps *jmps, size_t *offs, int *jmpc)
Definition: vm-x86.c:854
void potion_x86_stack(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, long need)
Definition: vm-x86.c:420
void potion_x86_getupval(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long lregs)
Definition: vm-x86.c:543
#define X86_PRE()
Definition: vm-x86.c:39
void potion_x86_global(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:559
#define ASM(ins)
Definition: asm.h:98
void potion_x86_gettuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:580
#define kh_exist(name, h, x)
Definition: khash.h:225
void potion_x86_setpath(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:663
#define PN_TUPLE_EACH(T, I, V, B)
Definition: potion.h:288
void potion_x86_newtuple(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:570
#define PN_HAS_UPVALS(v)
Definition: asm.h:88
PN potion_vm_eq(Potion *, PN, PN)
Definition: vm.c:416
#define PN_TUPLE_COUNT(T, I, B)
Definition: potion.h:280
#define PN_SIZE_T
Definition: config.h:26
void potion_x86_class(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos, long start)
Definition: vm-x86.c:1146
void potion_x86_gte(Potion *P, struct PNProto *volatile f, PNAsm *volatile *asmp, PN_SIZE pos)
Definition: vm-x86.c:782
PN potion_object_new(Potion *P, PN cl, PN self)
Definition: objmodel.c:522
#define ASMI(pn)
Definition: asm.h:100
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.
Definition: opcodes.h:70
PN potion_obj_div(Potion *P, PN a, PN b)
Definition: objmodel.c:448
#define PN_PROTO(x)
Definition: potion.h:227