3 * ================================================================
4 * SourcePawn (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ================================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
19 #include "opcode_helpers.h"
20 #include "x86_macros.h"
22 #define NUM_INFO_PARAMS 5
24 jitoffs_t Write_Execute_Function(JitWriter *jit)
27 * The variables we're passed in:
28 * sp_context_t *ctx, uint32_t code_idx, cell_t *result
33 * Currently, we do not accept ctx->frm as the new frame pointer.
34 * Instead, we copy the frame from the stack pointer.
35 * This is because we do not support resuming or sleeping!
40 IA32_Push_Reg(jit, REG_EBP);
41 IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
46 IA32_Push_Reg(jit, REG_ESI);
47 IA32_Push_Reg(jit, REG_EDI);
48 IA32_Push_Reg(jit, REG_EBX);
50 //sub esp, 4*n - reserve info array
51 //mov esi, esp - save info pointer
52 IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
53 IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
55 /* Initial memory setup */
56 //mov eax, [ebp+16] - get result pointer
57 //mov [esi+8], eax - store into info pointer
58 //mov eax, [ebp+8] - get context
59 //mov [esi+12], eax - store context into info pointer
60 //mov ecx, [eax+<offs>] - get heap pointer
61 //mov [esi+4], ecx - store heap into info pointer
62 //mov ebp, [eax+<offs>] - get data pointer
63 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
64 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
65 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
66 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
67 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
68 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
69 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory));
72 //mov edi, [eax+<offs>] - get stack pointer
73 //add edi, ebp - relocate to data section
74 //mov ebx, edi - copy sp to frm
75 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
76 IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
77 IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
79 /* Info memory setup */
80 //mov ecx, [eax+<offs>] - copy memsize to temp var
81 //add ecx, ebp - relocate
82 //mov [esi+x], ecx - store relocated
83 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, mem_size));
84 IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
85 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
87 /* Remaining needed vars */
88 //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
89 //add ecx, [eax+<offs>] - add code base to index
90 IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
91 IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
93 /* by now, everything is set up, so we can call into the plugin */
95 IA32_Call_Reg(jit, REG_ECX);
97 /* if the code flow gets to here, there was a normal return */
98 //mov ecx, [esi+8] - get retval pointer
99 //mov [ecx], eax - store retval from PRI
100 //mov eax, SP_ERROR_NONE - set no error
101 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
102 IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
103 IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
105 /* save where error checking/halting functions should go to */
106 jitoffs_t offs_return = jit->get_outputpos();
107 //mov esp, esi - restore stack pointer
108 IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
111 * We are going to restore SP, HP, and FRM for now. This is for
112 * debugging only, to check for alignment errors. As such:
113 * :TODO: probably remove this.
115 //mov ecx, [esi+context]
117 //mov edx, [esi+heap]
120 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
121 IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
122 IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
123 IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
124 IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
126 //add esp, 4*NUM_INFO_PARAMS
132 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
133 IA32_Pop_Reg(jit, REG_EBX);
134 IA32_Pop_Reg(jit, REG_EDI);
135 IA32_Pop_Reg(jit, REG_ESI);
136 IA32_Pop_Reg(jit, REG_EBP);
142 void Write_BreakDebug(JitWriter *jit)
147 //cmp [ecx+dbreak], 0
149 IA32_Push_Reg(jit, REG_EDI);
150 IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
151 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
152 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
153 jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
155 //:TODO: align the stack to 16bytes like in sysreq.x
156 /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
160 //mov ecx, [ecx+dbreak]
165 IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
166 IA32_Push_Reg(jit, AMX_REG_TMP);
167 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
168 IA32_Call_Reg(jit, AMX_REG_TMP);
169 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
175 IA32_Pop_Reg(jit, REG_EDI);
176 IA32_Send_Jump8_Here(jit, jmp);
180 void Write_GetError(JitWriter *jit)
182 CompData *data = (CompData *)jit->data;
184 //mov eax, [esi+info.context]
185 //mov eax, [eax+ctx.error]
187 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
188 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
189 IA32_Jump_Imm32_Abs(jit, data->jit_return);
192 void Write_SetError(JitWriter *jit, int error)
194 CompData *data = (CompData *)jit->data;
198 IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
199 IA32_Jump_Imm32_Abs(jit, data->jit_return);
202 void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
206 IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
207 IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
210 void Write_CheckHeap_Min(JitWriter *jit)
212 /* Check if the stack went beyond the heap low.
213 * This usually means there was a compiler error.
214 * NOTE: Special optimization here.
215 * The heap low is always known ahead of time! :)
217 CompData *data = (CompData *)jit->data;
218 //cmp [esi+info.heap], <heaplow>
220 IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
221 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
224 void Write_CheckHeap_Low(JitWriter *jit)
226 /* Check if the heap is trying to grow beyond the stack.
228 //mov ecx, [esi+info.heap]
229 //lea ecx, [ebp+ecx+STACK_MARGIN]
231 //ja :error ; I think this is right
232 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
233 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
234 IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
235 IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
238 void Write_CheckStack_Min(JitWriter *jit)
240 /* Check if the stack went beyond the stack top
241 * This usually means there was a compiler error.
243 //cmp edi, [esi+info.stacktop]
245 IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
246 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
249 void Write_CheckStack_Low(JitWriter *jit)
251 /* Check if the stack went beyond the heap boundary.
252 * Unfortunately this one isn't as quick as the other check.
253 * The stack margin check is important for sysreq.n having space.
255 //mov ecx, [esi+info.heap]
256 //lea ecx, [ebp+ecx+STACK_MARGIN]
258 //jb :error ; I think this is right
259 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
260 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
261 IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
262 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
265 void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
267 CompData *data = (CompData *)jit->data;
269 /* :TODO: Should this be checking for below heaplow?
270 * The old JIT did not.
274 if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
276 /* If we're not in the initial generation phase,
277 * Write a call to the actual routine instead.
279 if ((reg == REG_EAX) && data->jit_verify_addr_eax)
281 jitoffs_t call = IA32_Call_Imm32(jit, 0);
282 IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
284 } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
285 jitoffs_t call = IA32_Call_Imm32(jit, 0);
286 IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
293 * :TODO: If we can't find a nicer way of doing this,
294 * then scrap it on high optimizations. The second portion is not needed at all!
297 /* Part 1: Check if we're in the memory bounds */
300 IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
301 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
303 /* Part 2: Check if we're in the invalid region between HP and SP */
305 //cmp <reg>, [esi+info.heap]
307 //lea ecx, [ebp+<reg>]
311 IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
312 jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
313 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
314 IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
315 IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
316 IA32_Send_Jump8_Here(jit, jmp);
324 void Macro_PushN_Addr(JitWriter *jit, int i)
329 // lea ecx, [eax+<val>]
330 // mov [edi-4*i], ecx
336 IA32_Push_Reg(jit, AMX_REG_PRI);
337 IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
340 val = jit->read_cell();
341 if (val < SCHAR_MAX && val > SCHAR_MIN)
342 IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
344 IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
345 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
347 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
348 IA32_Pop_Reg(jit, AMX_REG_PRI);
351 void Macro_PushN_S(JitWriter *jit, int i)
354 // mov ecx, [ebx+<val>]
355 // mov [edi-4*i], ecx
362 val = jit->read_cell();
363 if (val < SCHAR_MAX && val > SCHAR_MIN)
364 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
366 IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
367 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
369 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
372 void Macro_PushN_C(JitWriter *jit, int i)
375 // mov [edi-4*i], <val>
381 IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
383 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
386 void Macro_PushN(JitWriter *jit, int i)
389 // mov ecx, [ebp+<val>]
390 // mov [edi-4*i], ecx
397 val = jit->read_cell();
398 if (val < SCHAR_MAX && val > SCHAR_MIN)
399 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
401 IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
402 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
404 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
407 void WriteOp_Sysreq_C_Function(JitWriter *jit)
409 /* The small daddy of the big daddy of opcodes.
412 CompData *data = (CompData *)jit->data;
414 /* save registers we will need */
416 IA32_Push_Reg(jit, AMX_REG_ALT);
418 /* Align the stack to 16 bytes */
423 IA32_Push_Reg(jit, REG_EBX);
424 IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
425 IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
426 IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
428 /* push some callback stuff */
430 //push ecx ; native index
431 IA32_Push_Reg(jit, AMX_REG_STK);
432 IA32_Push_Reg(jit, REG_ECX);
434 /* Relocate stack, heap, frm information, then store back */
435 //mov eax, [esi+context]
442 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
443 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
444 IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
445 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
446 IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
447 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
448 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
450 /* finally, push the last parameter and make the call */
452 //call NativeCallback
453 IA32_Push_Reg(jit, REG_EAX);
454 jitoffs_t call = IA32_Call_Imm32(jit, 0);
457 IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
459 IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
463 //mov ecx, [esi+context]
466 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
467 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
468 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
470 /* restore what we damaged */
475 IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
476 IA32_Pop_Reg(jit, REG_EBX);
477 IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
478 IA32_Pop_Reg(jit, AMX_REG_ALT);
484 void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero)
486 cell_t vectors = 1; /* we need one vector to start off with */
488 cell_t cur_write = 0;
489 cell_t dimcount = _dimcount;
491 /* Initialize rotation */
492 cur_write = dims[dimcount-1];
494 while (--dimcount >= 1)
496 cell_t cur_dim = dims[dimcount];
497 cell_t sub_dim = dims[dimcount-1];
498 for (cell_t i=0; i<vectors; i++)
500 for (cell_t j=0; j<cur_dim; j++)
502 arraybase[cur_offs] = (cur_write - cur_offs)*sizeof(cell_t);
504 cur_write += sub_dim;
510 /* everything after cur_offs can be zeroed */
514 for (ucell_t i=0; i<_dimcount; i++)
518 memset(&arraybase[cur_offs], 0, size*sizeof(cell_t));
525 * A few notes about this function.
526 * I was more concerned about efficient use of registers here, rather than
527 * fine-tuned optimization. The reason is that the code is already complicated,
528 * and it is very easy to mess up.
530 void WriteIntrinsic_GenArray(JitWriter *jit)
533 * save important values
538 //push ecx ;value is referenced on stack
539 IA32_Push_Reg(jit, REG_EBX);
540 IA32_Push_Reg(jit, REG_EAX);
541 IA32_Push_Reg(jit, REG_EDX);
542 IA32_Push_Reg(jit, REG_ECX);
545 * Calculate how many cells will be needed.
547 //mov edx, [edi] ;get last dimension's count
548 //mov eax, 1 ;position at second to last dimension
550 //cmp eax, [esp] ;compare to # of params
551 //jae :done ;end loop if done
552 //mov ecx, [edi+eax*4] ;get dimension size
553 //imul edx, ecx ;multiply by size
554 //add eax, 1 ;increment
555 //add edx, ecx ;add size (indirection vector)
556 //jmp :loop ;jump back
558 IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
559 IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
560 jitoffs_t loop1 = jit->get_outputpos();
561 IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
562 jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
563 IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
564 IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
565 IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
566 IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
567 IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
568 IA32_Send_Jump8_Here(jit, done1);
570 /* Test if we have heap space for this */
571 //mov eax, [esi+info.heap] ;get heap pointer
572 //lea eax, [eax+edx*4] ;new heap pointer
573 //cmp eax, <hlw> ;compare to heap low
574 //jbe :error ;die if we hit this (it should always be >)
575 //add eax, ebp ;relocate to stack
576 //cmp eax, edi ;die if above the stack pointer
578 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
579 IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
580 IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
581 IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
582 IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
583 IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
584 IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
586 /* Prepare for indirection iteration */
587 //mov eax, [esi+info.heap] ;get heap pointer
588 //lea ebx, [eax+edx*4] ;new heap pointer
589 //mov [esi+info.heap], ebx ;store back
590 //push eax ;save heap pointer - we need it
591 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
592 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
593 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
594 IA32_Push_Reg(jit, REG_EAX);
596 WriteOp_Tracker_Push_Reg(jit, REG_EDX);
598 /* This part is too messy to do in straight assembly.
599 * I'm letting the compiler handle it and thus it's in C.
601 //lea ebx, [ebp+eax] ;get base pointer
602 //push dword [esp-8] ;push autozero
603 //push dword [esp-8] ;push dimension count
604 //push edi ;push dim array
606 //call GenerateArrayIndirectionVectors
608 IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
609 IA32_Push_Rm_Disp8_ESP(jit, 8);
610 IA32_Push_Rm_Disp8_ESP(jit, 8);
611 IA32_Push_Reg(jit, REG_EDI);
612 IA32_Push_Reg(jit, REG_EBX);
613 IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
614 IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
616 /* Store the heap pointer back into the stack */
617 //pop eax ;restore heap pointer
618 //pop ecx ;restore param count
619 //lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
620 //mov [edi], eax ;store back the heap pointer
621 IA32_Pop_Reg(jit, REG_EAX);
622 IA32_Pop_Reg(jit, REG_ECX);
623 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
624 IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
626 /* Return to caller */
631 IA32_Pop_Reg(jit, REG_ECX);
632 IA32_Pop_Reg(jit, REG_EAX);
633 IA32_Pop_Reg(jit, REG_EBX);
637 void WriteOp_Sysreq_N_Function(JitWriter *jit)
639 /* The big daddy of opcodes.
643 CompData *data = (CompData *)jit->data;
645 /* store the number of parameters on the stack */
648 IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
649 IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
651 /* save registers we will need */
652 //push eax ; num_params for stack popping
654 IA32_Push_Reg(jit, REG_EAX);
655 IA32_Push_Reg(jit, AMX_REG_ALT);
657 /* Align the stack to 16 bytes */
662 IA32_Push_Reg(jit, REG_EBX);
663 IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
664 IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
665 IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
667 /* push some callback stuff */
669 //push ecx ; native index
670 IA32_Push_Reg(jit, AMX_REG_STK);
671 IA32_Push_Reg(jit, REG_ECX);
673 /* Relocate stack, heap, frm information, then store back */
674 //mov eax, [esi+context]
681 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
682 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
683 IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
684 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
685 IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
686 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
687 IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
689 /* finally, push the last parameter and make the call */
691 //call NativeCallback
692 IA32_Push_Reg(jit, REG_EAX);
693 jitoffs_t call = IA32_Call_Imm32(jit, 0);
696 IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
698 IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
702 //mov ecx, [esi+context]
705 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
706 IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
707 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
709 /* restore what we damaged */
714 //pop ecx ; num_params
715 IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
716 IA32_Pop_Reg(jit, REG_EBX);
717 IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
718 IA32_Pop_Reg(jit, AMX_REG_ALT);
719 IA32_Pop_Reg(jit, REG_ECX);
721 /* pop the AMX stack. do not check the margins.
722 * Note that this is not a true macro - we don't bother to
723 * set ALT here because nothing will be using it.
725 //lea edi, [edi+ecx*4+4]
726 IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
732 void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
734 CompData *data = (CompData *)jit->data;
736 /* Save registers that may be damaged by the call */
740 //lea edi, [<reg>*4] ; we want the count in bytes not in cells
741 IA32_Push_Reg(jit, AMX_REG_PRI);
744 IA32_Push_Reg(jit, AMX_REG_TMP);
746 IA32_Push_Reg(jit, AMX_REG_STK);
747 IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
749 /* Get the context ptr, push it and call the check */
750 //mov eax, [esi+context]
752 //call JIT_VerifyOrAllocateTracker
753 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
754 IA32_Push_Reg(jit, REG_EAX);
755 jitoffs_t call = IA32_Call_Imm32(jit, 0);
756 IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
758 /* Check for errors */
761 IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
762 IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
766 IA32_Pop_Reg(jit, REG_EAX);
768 /* Push the register into the stack and increment pCur */
769 //mov edx, [eax+vm[]]
770 //mov eax, [edx+pcur]
773 IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
774 IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
775 IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
776 IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
778 /* Restore PRI, ALT and STK */
782 IA32_Pop_Reg(jit, AMX_REG_STK);
785 IA32_Pop_Reg(jit, AMX_REG_TMP);
787 IA32_Pop_Reg(jit, AMX_REG_PRI);
790 int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
792 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
794 if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
796 return SP_ERROR_TRACKER_BOUNDS;
799 if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
801 size_t disp = trk->size - 1;
803 trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
807 return SP_ERROR_TRACKER_BOUNDS;
810 trk->pCur = trk->pBase + disp;
813 return SP_ERROR_NONE;
816 int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
818 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
820 if (trk->pCur <= trk->pBase)
822 return SP_ERROR_TRACKER_BOUNDS;
825 return SP_ERROR_NONE;
828 void Write_RoundingTable(JitWriter *jit)
830 jit->write_int32(-1);
835 void AlignMe(JitWriter *jit)
837 jitoffs_t cur_offs = jit->get_outputpos();
838 jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
842 for (jit_uint32_t i=0; i<offset; i++)
844 jit->write_ubyte(IA32_INT3);