diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index a916da7d..7318ccfe 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -958,6 +958,8 @@ inline void WriteOp_Heap_Pri(JitWriter *jit) //add [hea], eax IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Push_Heap_C(JitWriter *jit) @@ -969,6 +971,8 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Rm_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) @@ -979,6 +983,8 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); + + Write_CheckMargin_Heap(jit); } inline void WriteOp_Load_Both(JitWriter *jit) @@ -1215,6 +1221,20 @@ inline void WriteOp_Stack(JitWriter *jit) Write_CheckMargin_Stack(jit); } +inline void WriteOp_Heap(JitWriter *jit) +{ + //mov edx, hea + //add hea, + cell_t val = jit->read_cell(); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_INFO_FRM, AMX_INFO_HEAP); + if (val < SCHAR_MAX && val > SCHAR_MIN) + IA32_Add_Rm_Imm8_Disp8(jit, AMX_INFO_FRM, (jit_int8_t)val, AMX_INFO_HEAP); + else + IA32_Add_Rm_Imm32_Disp8(jit, AMX_INFO_FRM, val, AMX_INFO_HEAP); + + Write_CheckMargin_Heap(jit); +} + inline void WriteOp_SDiv(JitWriter *jit) { //mov ecx, edx @@ -1338,6 +1358,7 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); + cell_t jitpos; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1346,19 +1367,30 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) writer.outptr = NULL; writer.outbase = NULL; - /* Get inlining level */ - int inline_level = data->inline_level; - //:TODO: Jump back here once finished! + /* Initialize pass vars */ + data->jit_chkmargin_heap = 0; + data->jit_verify_addr_eax = 0; + data->jit_verify_addr_edx = 0; + /* Start writing the actual code */ data->jit_return = Write_Execute_Function(jit); /* Write error checking routines in case they are needed */ - data->jit_verify_addr_eax = jit->jit_curpos(); + jitpos = jit->jit_curpos(); Write_Check_VerifyAddr(jit, REG_EAX, true); - data->jit_verify_addr_edx = jit->jit_curpos(); + data->jit_verify_addr_eax = jitpos; + + jitpos = jit->jit_curpos(); Write_Check_VerifyAddr(jit, REG_EDX, true); + data->jit_verify_addr_edx = jitpos; + + jitpos = jit->jit_curpos(); + Write_CheckMargin_Heap(jit); + data->jit_chkmargin_heap = jitpos; + + /* Begin opcode browsing */ for (; writer.inptr <= endptr;) { @@ -1970,6 +2002,11 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) WriteOp_Stack(jit); break; } + case OP_HEAP: + { + WriteOp_Heap(jit); + break; + } case OP_SDIV: { WriteOp_SDiv(jit); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 5e53ee33..704367c9 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,6 +9,7 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) +#define STACK_MARGIN 16 class CompData : public ICompilation { @@ -22,6 +23,7 @@ public: jitoffs_t jit_return; jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; + jitoffs_t jit_chkmargin_heap; int inline_level; bool checks; bool debug; @@ -49,10 +51,11 @@ public: #define AMX_REG_INFO REG_ESI #define AMX_REG_FRM REG_EBX -#define AMX_INFO_FRM AMX_REG_INFO -#define AMX_INFO_HEAP 4 -#define AMX_INFO_RETVAL 8 -#define AMX_INFO_CONTEXT 12 -#define AMX_INFO_STACKTOP 16 +#define AMX_INFO_FRM AMX_REG_INFO //not relocated +#define AMX_INFO_HEAP 4 //not relocated +#define AMX_INFO_RETVAL 8 //physical +#define AMX_INFO_CONTEXT 12 //physical +#define AMX_INFO_STACKTOP 16 //relocated +#define AMX_INFO_HEAPLOW 20 //not relocated #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 795502d1..026b6611 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -32,27 +32,28 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); - //sub esp, 4*5 - allocate info array + //sub esp, 4*6 - allocate info array //mov esi, esp - save info pointer - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); - //mov eax, [ebp+16] - get result pointer - //mov [esi+8], eax - store into info pointer - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_RETVAL); - + /* Initial memory setup */ + //mov eax, [ebp+16] - get result pointer + //mov [esi+8], eax - store into info pointer //mov eax, [ebp+8] - get context //mov [esi+12], eax - store context into info pointer //mov ecx, [eax+] - get heap pointer //mov [esi+4], ecx - store heap into info pointer //mov edi, [eax+] - get data pointer + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_HEAP); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); + /* Frame setup */ //mov ebp, [eax+] - get stack pointer //add ebp, edi - relocate to data section //mov ebx, ebp - copy sp to frm @@ -60,13 +61,19 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); + /* Info memory setup */ //mov ecx, edi - copy base of data to temp var //add ecx, [eax+] - add memsize to get stack top //mov [esi+16], ecx - store stack top into info pointer + //mov ecx, [eax+] - get heap low + //mov [esi+20], ecx - store heap low into info pointer IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG); IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); - IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_STACKTOP); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase)); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW); + /* Remaining needed vars */ //mov ecx, [ebp+12] - get code index //add ecx, [eax+] - add code base to index //mov edx, [eax+] - get alt @@ -77,7 +84,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri)); /* by now, everything is set up, so we can call into the plugin */ - //call ecx IA32_Call_Rm(jit, REG_ECX); @@ -111,13 +117,13 @@ jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) * BaseContext::Execute() automatically restores our values anyway. */ - //add esp, 4*4 + //add esp, 4*6 //pop ebx //pop edi //pop esi //pop ebp //ret - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*5, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); IA32_Pop_Reg(jit, REG_EBX); IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); @@ -221,6 +227,53 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) } } +void Write_CheckMargin_Heap(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + + bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); + + if (always_inline && data->jit_chkmargin_heap) + { + /* just generate the call */ + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, data->jit_chkmargin_heap); + } else { + //mov ecx, [esi+hea] + //cmp ecx, [esi+hlw] + //jl :error_heapmin + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Cmp_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_HEAPLOW); + jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); + //lea ecx, [edi+ecx+STACK_MARGIN] + //cmp ecx, ebp + // jg :error_heaplow + //OR + // ret + IA32_Lea_Reg_DispRegMultImm8(jit, REG_ECX, AMX_REG_DAT, REG_ECX, NOSCALE, STACK_MARGIN); + IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG); + jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0); + jitoffs_t cont; + if (always_inline) + { + cont = IA32_Jump_Imm8(jit, 0); + } else { + IA32_Return(jit); + } + //:error_heapmin + IA32_Send_Jump8_Here(jit, hm); + Write_Error(jit, SP_ERR_HEAPMIN); + //:error_heaplow + IA32_Send_Jump8_Here(jit, hl); + Write_Error(jit, SP_ERR_HEAPLOW); + //:continue + if (!always_inline) + { + IA32_Send_Jump8_Here(jit, cont); + } + } +} + void Write_CheckMargin_Stack(JitWriter *jit) { /* this is small, so we always inline it. diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 9a56da08..51f8619c 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -19,6 +19,7 @@ void Write_Error(JitWriter *jit, int error); /** * Verifies an address by register. + * :TODO: optimize and make it look like the heap checkfunction! */ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); @@ -27,6 +28,10 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); */ void Write_CheckMargin_Stack(JitWriter *jit); +/** + * Verifies heap margins. + */ +void Write_CheckMargin_Heap(JitWriter *jit); /** * Checks for division by zero. */ @@ -88,7 +93,7 @@ typedef enum OP_POP_PRI, //DONE OP_POP_ALT, //DONE OP_STACK, //DONE - OP_HEAP, + OP_HEAP, //DONE OP_PROC, //DONE OP_RET, OP_RETN,