5 #include "opcode_helpers.h"
6 #include "x86_macros.h"
8 #define NUM_INFO_PARAMS 5
10 jitoffs_t Write_Execute_Function(JitWriter *jit)
13 * The variables we're passed in:
14 * sp_context_t *ctx, uint32_t code_idx, cell_t *result
19 * Currently, we do not accept ctx->frm as the new frame pointer.
20 * Instead, we copy the frame from the stack pointer.
21 * This is because we do not support resuming or sleeping!
26 IA32_Push_Reg(jit, REG_EBP);
27 IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
32 IA32_Push_Reg(jit, REG_ESI);
33 IA32_Push_Reg(jit, REG_EDI);
34 IA32_Push_Reg(jit, REG_EBX);
36 //sub esp, 4*n - reserve info array
37 //mov esi, esp - save info pointer
38 IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
39 IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
41 /* Initial memory setup */
42 //mov eax, [ebp+16] - get result pointer
43 //mov [esi+8], eax - store into info pointer
44 //mov eax, [ebp+8] - get context
45 //mov [esi+12], eax - store context into info pointer
46 //mov ecx, [eax+<offs>] - get heap pointer
47 //mov [esi+4], ecx - store heap into info pointer
48 //mov ebp, [eax+<offs>] - get data pointer
49 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
50 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
51 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
52 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
53 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
54 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
55 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory));
58 //mov edi, [eax+<offs>] - get stack pointer
59 //add edi, ebp - relocate to data section
60 //mov ebx, edi - copy sp to frm
61 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
62 IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
63 IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
65 /* Info memory setup */
66 //mov ecx, [eax+<offs>] - copy memsize to temp var
67 //add ecx, ebp - relocate
68 //mov [esi+x], ecx - store relocated
69 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
70 IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
71 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
73 /* Remaining needed vars */
74 //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
75 //add ecx, [eax+<offs>] - add code base to index
76 IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
77 IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
79 /* by now, everything is set up, so we can call into the plugin */
81 IA32_Call_Reg(jit, REG_ECX);
83 /* if the code flow gets to here, there was a normal return */
84 //mov ecx, [esi+8] - get retval pointer
85 //mov [ecx], eax - store retval from PRI
86 //mov eax, SP_ERROR_NONE - set no error
87 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
88 IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
89 IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
91 /* save where error checking/halting functions should go to */
92 jitoffs_t offs_return = jit->get_outputpos();
93 //mov esp, esi - restore stack pointer
94 IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
97 * We are going to restore SP, HP, and FRM for now. This is for
98 * debugging only, to check for alignment errors. As such:
99 * :TODO: probably remove this.
101 //mov ecx, [esi+context]
103 //mov edx, [esi+heap]
106 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
107 IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
108 IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
109 IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
110 IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
112 //add esp, 4*NUM_INFO_PARAMS
118 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
119 IA32_Pop_Reg(jit, REG_EBX);
120 IA32_Pop_Reg(jit, REG_EDI);
121 IA32_Pop_Reg(jit, REG_ESI);
122 IA32_Pop_Reg(jit, REG_EBP);
128 void Write_BreakDebug(JitWriter *jit)
133 //cmp [ecx+dbreak], 0
135 IA32_Push_Reg(jit, REG_EDI);
136 IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
137 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
138 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
139 jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
141 /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
145 //mov ecx, [ecx+dbreak]
150 IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
151 IA32_Push_Reg(jit, AMX_REG_TMP);
152 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
153 IA32_Call_Reg(jit, AMX_REG_TMP);
154 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
160 IA32_Pop_Reg(jit, REG_EDI);
161 IA32_Send_Jump8_Here(jit, jmp);
165 void Write_GetError(JitWriter *jit)
167 CompData *data = (CompData *)jit->data;
169 //mov eax, [esi+info.context]
170 //mov eax, [eax+ctx.error]
172 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
173 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
174 IA32_Jump_Imm32_Abs(jit, data->jit_return);
177 void Write_SetError(JitWriter *jit, int error)
179 CompData *data = (CompData *)jit->data;
183 IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
184 IA32_Jump_Imm32_Abs(jit, data->jit_return);
187 void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
191 IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
192 IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
195 void Write_CheckHeap_Min(JitWriter *jit)
197 /* Check if the stack went beyond the heap low.
198 * This usually means there was a compiler error.
199 * NOTE: Special optimization here.
200 * The heap low is always known ahead of time! :)
202 CompData *data = (CompData *)jit->data;
203 //cmp [esi+info.heap], <heaplow>
205 IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
206 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
209 void Write_CheckHeap_Low(JitWriter *jit)
211 /* Check if the heap is trying to grow beyond the stack.
213 //mov ecx, [esi+info.heap]
214 //lea ecx, [ebp+ecx+STACK_MARGIN]
216 //ja :error ; I think this is right
217 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
218 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
219 IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
220 IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
223 void Write_CheckStack_Min(JitWriter *jit)
225 /* Check if the stack went beyond the stack top
226 * This usually means there was a compiler error.
228 //cmp edi, [esi+info.stacktop]
230 IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
231 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
234 void Write_CheckStack_Low(JitWriter *jit)
236 /* Check if the stack went beyond the heap boundary.
237 * Unfortunately this one isn't as quick as the other check.
238 * The stack margin check is important for sysreq.n having space.
240 //mov ecx, [esi+info.heap]
241 //lea ecx, [ebp+ecx+STACK_MARGIN]
243 //jb :error ; I think this is right
244 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
245 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
246 IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
247 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
250 void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
252 CompData *data = (CompData *)jit->data;
254 /* :TODO: Should this be checking for below heaplow?
255 * The old JIT did not.
259 if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
261 /* If we're not in the initial generation phase,
262 * Write a call to the actual routine instead.
264 if ((reg == REG_EAX) && data->jit_verify_addr_eax)
266 jitoffs_t call = IA32_Call_Imm32(jit, 0);
267 IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
269 } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
270 jitoffs_t call = IA32_Call_Imm32(jit, 0);
271 IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
278 * :TODO: If we can't find a nicer way of doing this,
279 * then scrap it on high optimizations. The second portion is not needed at all!
282 /* Part 1: Check if we're in the memory bounds */
285 IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
286 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
288 /* Part 2: Check if we're in the invalid region between HP and SP */
290 //cmp <reg>, [esi+info.heap]
292 //lea ecx, [ebp+<reg>]
296 IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
297 jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
298 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
299 IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
300 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
301 IA32_Send_Jump8_Here(jit, jmp);
309 void Macro_PushN_Addr(JitWriter *jit, int i)
314 // lea ecx, [eax+<val>]
315 // mov [edi-4*i], ecx
321 IA32_Push_Reg(jit, AMX_REG_PRI);
322 IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
325 val = jit->read_cell();
326 if (val < SCHAR_MAX && val > SCHAR_MIN)
327 IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
329 IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
330 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
332 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
333 IA32_Pop_Reg(jit, AMX_REG_PRI);
336 void Macro_PushN_S(JitWriter *jit, int i)
339 // mov ecx, [ebx+<val>]
340 // mov [edi-4*i], ecx
347 val = jit->read_cell();
348 if (val < SCHAR_MAX && val > SCHAR_MIN)
349 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
351 IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
352 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
354 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
357 void Macro_PushN_C(JitWriter *jit, int i)
360 // mov [edi-4*i], <val>
366 IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
368 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
371 void Macro_PushN(JitWriter *jit, int i)
374 // mov ecx, [ebp+<val>]
375 // mov [edi-4*i], ecx
382 val = jit->read_cell();
383 if (val < SCHAR_MAX && val > SCHAR_MIN)
384 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
386 IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
387 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
389 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
392 void WriteOp_Sysreq_C_Function(JitWriter *jit)
394 /* The small daddy of the big daddy of opcodes.
397 CompData *data = (CompData *)jit->data;
399 /* save registers we will need */
401 IA32_Push_Reg(jit, AMX_REG_ALT);
403 /* push some callback stuff */
405 //push ecx ; native index
406 IA32_Push_Reg(jit, AMX_REG_STK);
407 IA32_Push_Reg(jit, REG_ECX);
409 /* Relocate stack, heap, frm information, then store back */
410 //mov eax, [esi+context]
417 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
418 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
419 IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
420 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
421 IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
422 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
423 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
425 /* finally, push the last parameter and make the call */
427 //call NativeCallback
428 IA32_Push_Reg(jit, REG_EAX);
429 jitoffs_t call = IA32_Call_Imm32(jit, 0);
432 IA32_Write_Jump32_Abs(jit, call, NativeCallback);
434 IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug);
438 //mov ecx, [esi+context]
441 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
442 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
443 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
445 /* restore what we damaged */
449 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
450 IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
451 IA32_Pop_Reg(jit, AMX_REG_ALT);
457 void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero)
459 cell_t vectors = 1; /* we need one vector to start off with */
461 cell_t cur_write = 0;
462 cell_t dimcount = _dimcount;
464 /* Initialize rotation */
465 cur_write = dims[dimcount-1];
467 while (--dimcount >= 1)
469 cell_t cur_dim = dims[dimcount];
470 cell_t sub_dim = dims[dimcount-1];
471 for (cell_t i=0; i<vectors; i++)
473 for (cell_t j=0; j<cur_dim; j++)
475 arraybase[cur_offs] = (cur_write - cur_offs)*sizeof(cell_t);
477 cur_write += sub_dim;
483 /* everything after cur_offs can be zeroed */
487 for (ucell_t i=0; i<_dimcount; i++)
491 memset(&arraybase[cur_offs], 0, size*sizeof(cell_t));
498 * A few notes about this function.
499 * I was more concerned about efficient use of registers here, rather than
500 * fine-tuned optimization. The reason is that the code is already complicated,
501 * and it is very easy to mess up.
503 void WriteIntrinsic_GenArray(JitWriter *jit)
506 * save important values
511 //push ecx ;value is referenced on stack
512 IA32_Push_Reg(jit, REG_EBX);
513 IA32_Push_Reg(jit, REG_EAX);
514 IA32_Push_Reg(jit, REG_EDX);
515 IA32_Push_Reg(jit, REG_ECX);
518 * Calculate how many cells will be needed.
520 //mov edx, [edi] ;get last dimension's count
521 //mov eax, 1 ;position at second to last dimension
523 //cmp eax, [esp] ;compare to # of params
524 //jae :done ;end loop if done
525 //mov ecx, [edi+eax*4] ;get dimension size
526 //imul edx, ecx ;multiply by size
527 //add eax, 1 ;increment
528 //add edx, ecx ;add size (indirection vector)
529 //jmp :loop ;jump back
531 IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
532 IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
533 jitoffs_t loop1 = jit->get_outputpos();
534 IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
535 jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
536 IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
537 IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
538 IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
539 IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
540 IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
541 IA32_Send_Jump8_Here(jit, done1);
543 /* Test if we have heap space for this */
544 //mov eax, [esi+info.heap] ;get heap pointer
545 //lea eax, [eax+edx*4] ;new heap pointer
546 //cmp eax, <hlw> ;compare to heap low
547 //jbe :error ;die if we hit this (it should always be >)
548 //add eax, ebp ;relocate to stack
549 //cmp eax, edi ;die if above the stack pointer
551 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
552 IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
553 IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
554 IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
555 IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
556 IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
557 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
559 /* Prepare for indirection iteration */
560 //mov eax, [esi+info.heap] ;get heap pointer
561 //lea ebx, [eax+edx*4] ;new heap pointer
562 //mov [esi+info.heap], ebx ;store back
563 //push eax ;save heap pointer - we need it
564 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
565 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
566 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
567 IA32_Push_Reg(jit, REG_EAX);
569 WriteOp_Tracker_Push_Reg(jit, REG_EDX);
571 /* This part is too messy to do in straight assembly.
572 * I'm letting the compiler handle it and thus it's in C.
574 //lea ebx, [ebp+eax] ;get base pointer
575 //push dword [esp-8] ;push autozero
576 //push dword [esp-8] ;push dimension count
577 //push edi ;push dim array
579 //call GenerateArrayIndirectionVectors
581 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
582 IA32_Push_Rm_Disp8_ESP(jit, 8);
583 IA32_Push_Rm_Disp8_ESP(jit, 8);
584 IA32_Push_Reg(jit, REG_EDI);
585 IA32_Push_Reg(jit, REG_EBX);
586 IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
587 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
589 /* Store the heap pointer back into the stack */
590 //pop eax ;restore heap pointer
591 //pop ecx ;restore param count
592 //lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
593 //mov [edi], eax ;store back the heap pointer
594 IA32_Pop_Reg(jit, REG_EAX);
595 IA32_Pop_Reg(jit, REG_ECX);
596 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
597 IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
599 /* Return to caller */
604 IA32_Pop_Reg(jit, REG_ECX);
605 IA32_Pop_Reg(jit, REG_EAX);
606 IA32_Pop_Reg(jit, REG_EBX);
610 void WriteOp_Sysreq_N_Function(JitWriter *jit)
612 /* The big daddy of opcodes.
616 CompData *data = (CompData *)jit->data;
618 /* store the number of parameters on the stack */
621 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
622 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
624 /* save registers we will need */
625 //push eax ; num_params for stack popping
627 IA32_Push_Reg(jit, REG_EAX);
628 IA32_Push_Reg(jit, AMX_REG_ALT);
630 /* push some callback stuff */
632 //push ecx ; native index
633 IA32_Push_Reg(jit, AMX_REG_STK);
634 IA32_Push_Reg(jit, REG_ECX);
636 /* Relocate stack, heap, frm information, then store back */
637 //mov eax, [esi+context]
644 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
645 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
646 IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
647 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
648 IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
649 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
650 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
652 /* finally, push the last parameter and make the call */
654 //call NativeCallback
655 IA32_Push_Reg(jit, REG_EAX);
656 jitoffs_t call = IA32_Call_Imm32(jit, 0);
659 IA32_Write_Jump32_Abs(jit, call, NativeCallback);
661 IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug);
665 //mov ecx, [esi+context]
668 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
669 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
670 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
672 /* restore what we damaged */
676 //pop ecx ; num_params
677 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
678 IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
679 IA32_Pop_Reg(jit, AMX_REG_ALT);
680 IA32_Pop_Reg(jit, REG_ECX);
682 /* pop the AMX stack. do not check the margins.
683 * Note that this is not a true macro - we don't bother to
684 * set ALT here because nothing will be using it.
686 //lea edi, [edi+ecx*4+4]
687 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
693 void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
695 CompData *data = (CompData *)jit->data;
697 /* Save registers that may be damaged by the call */
701 //lea edi, [<reg>*4] ; we want the count in bytes not in cells
702 IA32_Push_Reg(jit, AMX_REG_PRI);
705 IA32_Push_Reg(jit, AMX_REG_TMP);
707 IA32_Push_Reg(jit, AMX_REG_STK);
708 IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
710 /* Get the context ptr, push it and call the check */
711 //mov eax, [esi+context]
713 //call JIT_VerifyOrAllocateTracker
714 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
715 IA32_Push_Reg(jit, REG_EAX);
716 jitoffs_t call = IA32_Call_Imm32(jit, 0);
717 IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
719 /* Check for errors */
722 IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
723 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
727 IA32_Pop_Reg(jit, REG_EAX);
729 /* Push the register into the stack and increment pCur */
730 //mov edx, [eax+vm[]]
731 //mov eax, [edx+pcur]
734 IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
735 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
736 IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
737 IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
739 /* Restore PRI, ALT and STK */
743 IA32_Pop_Reg(jit, AMX_REG_STK);
746 IA32_Pop_Reg(jit, AMX_REG_TMP);
748 IA32_Pop_Reg(jit, AMX_REG_PRI);
751 int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
753 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
755 if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
757 return SP_ERROR_TRACKER_BOUNDS;
760 if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
762 size_t disp = trk->size - 1;
764 trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
768 return SP_ERROR_TRACKER_BOUNDS;
771 trk->pCur = trk->pBase + disp;
774 return SP_ERROR_NONE;
777 int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
779 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
781 if (trk->pCur <= trk->pBase)
783 return SP_ERROR_TRACKER_BOUNDS;
786 return SP_ERROR_NONE;