diff --git a/sourcepawn/vm/jit/jit_helpers.h b/sourcepawn/vm/jit/jit_helpers.h index d0bf929d4..d6b4b8105 100644 --- a/sourcepawn/vm/jit/jit_helpers.h +++ b/sourcepawn/vm/jit/jit_helpers.h @@ -42,7 +42,7 @@ public: } inline void write_ubyte(jit_uint8_t c) { - if (outptr) + if (outbase) { *outptr = c; } @@ -50,7 +50,7 @@ public: } inline void write_byte(jit_int8_t c) { - if (outptr) + if (outbase) { *outptr = c; } @@ -58,7 +58,7 @@ public: } inline void write_int32(jit_int32_t c) { - if (outptr) + if (outbase) { *(jit_int32_t *)outptr = c; } @@ -66,21 +66,21 @@ public: } inline void write_uint32(jit_uint32_t c) { - if (outptr) + if (outbase) { *(jit_uint32_t *)outptr = c; } outptr += sizeof(jit_uint32_t); } - inline jitoffs_t jit_curpos() + inline jitoffs_t get_outputpos() { return (outptr - outbase); } - inline void setpos(jitoffs_t offs) + inline void set_outputpos(jitoffs_t offs) { outptr = outbase + offs; } - inline jitoffs_t inputrel() + inline jitoffs_t get_inputpos() { return (jitoffs_t)((char *)inptr - (char *)inbase); } diff --git a/sourcepawn/vm/jit/x86/dll_exports.cpp b/sourcepawn/vm/jit/x86/dll_exports.cpp index e1723f9e8..db593b19c 100644 --- a/sourcepawn/vm/jit/x86/dll_exports.cpp +++ b/sourcepawn/vm/jit/x86/dll_exports.cpp @@ -1 +1,33 @@ #include +#include "jit_x86.h" +#include "dll_exports.h" + +SourcePawn::ISourcePawnEngine *engine = NULL; +JITX86 jit; + +EXPORTFUNC void GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p) +{ + engine = engine_p; +} + +EXPORTFUNC unsigned int GetExportCount() +{ + return 0; +} + +EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum) +{ + /* Don't return anything if we're not initialized yet */ + if (!engine) + { + return NULL; + } + + /* We only have one export - 0 */ + if (exportnum) + { + return NULL; + } + + return &jit; +} diff --git a/sourcepawn/vm/jit/x86/dll_exports.h b/sourcepawn/vm/jit/x86/dll_exports.h index 568ecd922..653773f6e 100644 --- a/sourcepawn/vm/jit/x86/dll_exports.h +++ b/sourcepawn/vm/jit/x86/dll_exports.h @@ -3,6 +3,14 @@ #include - +#if defined WIN32 +#define EXPORTFUNC extern "C" __declspec(dllexport) +#elif defined __GNUC__ +#if __GNUC__ >= 3 +#define EXPORTFUNC extern "C" __attribute__((visibility("default"))) +#else +#define EXPORTFUNC extern "C" +#endif //__GNUC__ >= 3 +#endif //defined __GNUC__ #endif //_INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_ diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index e4b772136..b28619f9e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -37,9 +37,11 @@ inline void WriteOp_Push(JitWriter *jit) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); //optimize encoding a bit... if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); } @@ -219,13 +221,31 @@ inline void WriteOp_Sub_Alt(JitWriter *jit) inline void WriteOp_Proc(JitWriter *jit) { + /* align this to four byte boundaries! + * This is a decent optimization - x86 likes calls to be properly aligned, otherwise there's an alignment exception + * Since all calls are jumped to by relocation, the nops/garbage will never be hit by the runtime process. + * Just in case, we guard this memory with INT3 to break into the debugger. + */ + jitoffs_t cur_offs = jit->get_outputpos(); + if (cur_offs % 4) + { + cur_offs = 4 - (cur_offs % 4); + for (unsigned int i=0; iwrite_ubyte(IA32_INT3); + } + /* add this amt to the offset we relocated */ + jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t); + jitcode_t rebase = ((CompData *)jit->data)->rebase; + *(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos(); + } //push old frame on stack: - //sub edi, 4 //mov ecx, [esi+frm] - //mov [edi], ecx - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + //mov [edi-4], ecx + //sub edi, 8 ;extra un-used slot for non-existant CIP IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); //save frame: //:TODO: move to a temp reg, subtract and then move to mem, faster?? //mov [esi+frm], edi - get new frame @@ -244,7 +264,7 @@ inline void WriteOp_Lidx_B(JitWriter *jit) //mov eax, [ebp+eax] IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -538,9 +558,11 @@ inline void WriteOp_Dec(JitWriter *jit) //sub [ebp+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); - else + } else { IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); + } } inline void WriteOp_Dec_S(JitWriter *jit) @@ -548,9 +570,11 @@ inline void WriteOp_Dec_S(JitWriter *jit) //sub [ebx+], 1 cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); - else + } else { IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); + } } inline void WriteOp_Dec_I(JitWriter *jit) @@ -564,9 +588,11 @@ inline void WriteOp_Load_Pri(JitWriter *jit) //mov eax, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); + } } inline void WriteOp_Load_Alt(JitWriter *jit) @@ -574,9 +600,11 @@ inline void WriteOp_Load_Alt(JitWriter *jit) //mov edx, [ebp+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); + } } inline void WriteOp_Load_S_Pri(JitWriter *jit) @@ -584,9 +612,11 @@ inline void WriteOp_Load_S_Pri(JitWriter *jit) //mov eax, [ebx+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); + } } inline void WriteOp_Load_S_Alt(JitWriter *jit) @@ -594,9 +624,11 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit) //mov edx, [ebx+] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); + } } inline void WriteOp_Lref_Pri(JitWriter *jit) @@ -605,9 +637,11 @@ inline void WriteOp_Lref_Pri(JitWriter *jit) //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -617,9 +651,11 @@ inline void WriteOp_Lref_Alt(JitWriter *jit) //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } @@ -629,9 +665,11 @@ inline void WriteOp_Lref_S_Pri(JitWriter *jit) //mov eax, [ebp+eax] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } @@ -641,9 +679,11 @@ inline void WriteOp_Lref_S_Alt(JitWriter *jit) //mov edx, [ebp+edx] cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); + } IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); } @@ -668,9 +708,11 @@ inline void WriteOp_Addr_Pri(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Eax_Imm32(jit, val); + } } inline void WriteOp_Addr_Alt(JitWriter *jit) @@ -680,9 +722,11 @@ inline void WriteOp_Addr_Alt(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG); + } } inline void WriteOp_Stor_Pri(JitWriter *jit) @@ -690,9 +734,11 @@ inline void WriteOp_Stor_Pri(JitWriter *jit) //mov [ebp+], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val); + } } inline void WriteOp_Stor_Alt(JitWriter *jit) @@ -700,9 +746,11 @@ inline void WriteOp_Stor_Alt(JitWriter *jit) //mov [ebp+], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val); + } } inline void WriteOp_Stor_S_Pri(JitWriter *jit) @@ -710,9 +758,11 @@ inline void WriteOp_Stor_S_Pri(JitWriter *jit) //mov [ebx+], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val); + } } inline void WriteOp_Stor_S_Alt(JitWriter *jit) @@ -720,9 +770,11 @@ inline void WriteOp_Stor_S_Alt(JitWriter *jit) //mov [ebx+], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val); - else + } else { IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val); + } } inline void WriteOp_Idxaddr(JitWriter *jit) @@ -737,9 +789,11 @@ inline void WriteOp_Sref_Pri(JitWriter *jit) //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } @@ -749,9 +803,11 @@ inline void WriteOp_Sref_Alt(JitWriter *jit) //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } @@ -761,9 +817,11 @@ inline void WriteOp_Sref_S_Pri(JitWriter *jit) //mov [ebp+ecx], eax cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); } @@ -773,9 +831,11 @@ inline void WriteOp_Sref_S_Alt(JitWriter *jit) //mov [ebp+ecx], edx cell_t val = jit->read_cell(); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val); - else + } else { IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); + } IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); } @@ -901,7 +961,8 @@ inline void WriteOp_Heap_Pri(JitWriter *jit) 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); + /* :TODO: should we do a full bounds check here? */ + Write_CheckHeap_Min(jit); } inline void WriteOp_Push_Heap_C(JitWriter *jit) @@ -914,7 +975,7 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit) IA32_Mov_RmEBP_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); + Write_CheckHeap_Low(jit); } inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) @@ -926,13 +987,13 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit) IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); - Write_CheckMargin_Heap(jit); + Write_CheckHeap_Min(jit); } inline void WriteOp_Load_Both(JitWriter *jit) { - WriteOp_Const_Pri(jit); - WriteOp_Const_Alt(jit); + WriteOp_Load_Pri(jit); + WriteOp_Load_Alt(jit); } inline void WriteOp_Load_S_Both(JitWriter *jit) @@ -970,14 +1031,14 @@ inline void WriteOp_Const_S(JitWriter *jit) inline void WriteOp_Load_I(JitWriter *jit) { //mov eax, [ebp+eax] - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stor_I(JitWriter *jit) { //mov [ebp+edx], eax - Write_Check_VerifyAddr(jit, AMX_REG_ALT, false); + Write_Check_VerifyAddr(jit, AMX_REG_ALT); IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); } @@ -986,24 +1047,34 @@ inline void WriteOp_Lidx(JitWriter *jit) //lea eax, [edx+4*eax] //mov eax, [ebp+eax] IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); - Write_Check_VerifyAddr(jit, AMX_REG_PRI, false); + Write_Check_VerifyAddr(jit, AMX_REG_PRI); IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); } inline void WriteOp_Stack(JitWriter *jit) { + /* :TODO: Find an instance in the compiler where + * the ALT value from STACK is actually used! + */ //mov edx, edi //add edi, //sub edx, ebp cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); - else + } else { IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); + } IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); - Write_CheckMargin_Stack(jit); + if (val > 0) + { + Write_CheckStack_Min(jit); + } else if (val < 0) { + Write_CheckStack_Low(jit); + } } inline void WriteOp_Heap(JitWriter *jit) @@ -1013,11 +1084,19 @@ inline void WriteOp_Heap(JitWriter *jit) cell_t val = jit->read_cell(); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); if (val < SCHAR_MAX && val > SCHAR_MIN) + { IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP); - else + } else { IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP); + } - Write_CheckMargin_Heap(jit); + /* NOTE: Backwards from op.stack */ + if (val > 0) + { + Write_CheckHeap_Low(jit); + } else if (val < 0) { + Write_CheckHeap_Min(jit); + } } inline void WriteOp_SDiv(JitWriter *jit) @@ -1048,24 +1127,23 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit) inline void WriteOp_Retn(JitWriter *jit) { - //mov ebx, [edi] - get old frm - //mov ecx, [edi+4] - get return eip + //mov ebx, [edi+4] - get old frm //add edi, 8 - pop stack //mov [esi+frm], ebx - restore frame pointer //add ebx, ebp - relocate - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG); IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG); - //add edi, [edi] - reduce by this # of params - //add edi, 4 - pop one extra for the # itself - IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + /* pop params */ + //mov ecx, [edi] + //lea edi, [edi+edi*4+4] + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4); - //jmp ecx - jump to return eip - IA32_Jump_Reg(jit, AMX_REG_TMP); + //ret - return (EIP on real stack!) + IA32_Return(jit); } inline void WriteOp_Call(JitWriter *jit) @@ -1078,7 +1156,12 @@ inline void WriteOp_Call(JitWriter *jit) inline void WriteOp_Bounds(JitWriter *jit) { - Write_BoundsCheck(jit); + cell_t val = jit->read_cell(); + + //cmp eax, + //ja :error + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, val); + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds); } inline void WriteOp_Halt(JitWriter *jit) @@ -1095,14 +1178,7 @@ inline void WriteOp_Halt(JitWriter *jit) jit->read_cell(); CompData *data = (CompData *)jit->data; - jitoffs_t reloc; - if (data->inline_level & JIT_INLINE_ERRORCHECKS) - { - reloc = IA32_Jump_Imm32(jit, 0); - } else { - reloc = IA32_Call_Imm32(jit, 0); - } - IA32_Write_Jump32(jit, reloc, data->jit_return); + IA32_Jump_Imm32_Abs(jit, data->jit_return); } inline void WriteOp_Break(JitWriter *jit) @@ -1112,10 +1188,10 @@ inline void WriteOp_Break(JitWriter *jit) { //mov ecx, jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); - jitoffs_t save = jit->jit_curpos(); - jit->setpos(wr); + jitoffs_t save = jit->get_outputpos(); + jit->set_outputpos(wr); jit->write_uint32((uint32_t)(jit->outbase + wr)); - jit->setpos(save); + jit->set_outputpos(save); wr = IA32_Call_Imm32(jit, 0); IA32_Write_Jump32(jit, wr, data->jit_break); @@ -1126,7 +1202,6 @@ inline void WriteOp_Jump(JitWriter *jit) { //jmp cell_t amx_offs = jit->read_cell(); - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false)); } @@ -1163,7 +1238,7 @@ inline void WriteOp_Jneq(JitWriter *jit) //jne cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_NE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false)); } inline void WriteOp_Jsless(JitWriter *jit) @@ -1172,7 +1247,7 @@ inline void WriteOp_Jsless(JitWriter *jit) //jl cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_L, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false)); } inline void WriteOp_Jsleq(JitWriter *jit) @@ -1181,7 +1256,7 @@ inline void WriteOp_Jsleq(JitWriter *jit) //jle cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_LE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false)); } inline void WriteOp_JsGrtr(JitWriter *jit) @@ -1190,7 +1265,7 @@ inline void WriteOp_JsGrtr(JitWriter *jit) //jg cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_G, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false)); } inline void WriteOp_JsGeq(JitWriter *jit) @@ -1199,7 +1274,7 @@ inline void WriteOp_JsGeq(JitWriter *jit) //jge cell_t target = jit->read_cell(); IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32(jit, CC_GE, RelocLookup(jit, target, false)); + IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false)); } inline void WriteOp_Switch(JitWriter *jit) @@ -1279,10 +1354,10 @@ inline void WriteOp_Switch(JitWriter *jit) jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); /* The case table starts here. Go back and write the output pointer. */ - jitoffs_t cur_pos = jit->jit_curpos(); - jit->setpos(tbl_offs); + jitoffs_t cur_pos = jit->get_outputpos(); + jit->set_outputpos(tbl_offs); jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos)); - jit->setpos(cur_pos); + jit->set_outputpos(cur_pos); //now we can write the case table, finally! jit_uint32_t base = (jit_uint32_t)jit->outbase; for (cell_t i=0; iwrite_ubyte(IA32_INT3); } } @@ -1321,6 +1398,98 @@ inline void WriteOp_Casetbl(JitWriter *jit) jit->inptr += num_cases; } +inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit) +{ + /* store the number of parameters on the stack, + * and store the native index as well. + */ + cell_t num_params = jit->read_cell(); + cell_t native_index = jit->read_cell(); + + //mov eax, + //mov ecx, + IA32_Mov_Rm_Imm32(jit, REG_EAX, num_params, MOD_REG); + IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG); + + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n); +} + +inline void WriteOp_Sysreq_N(JitWriter *jit) +{ + /* The big daddy of opcodes. */ + cell_t num_params = jit->read_cell(); + cell_t native_index = jit->read_cell(); + CompData *data = (CompData *)jit->data; + + /* store the number of parameters on the stack */ + //mov [edi-4], num_params + //sub edi, 4 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + + /* save registers we will need */ + //push edx + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* push some callback stuff */ + //push edi ; stack + //push ; native index + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Push_Imm32(jit, native_index); + + /* Relocate stack, heap, frm information, then store back */ + //sub edi, ebp + //mov ecx, [esi+hea] + //mov eax, [esi+context] + //mov [eax+hp], ecx + //mov [eax+sp], edi + //mov ecx, [esi+frm] + //mov [eax+frm], ecx + IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); + + /* finally, push the last parameter and make the call */ + //push eax ; context + //mov eax, [eax+context] + //call NativeCallback + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + + /* restore what we damaged */ + //add esp, 4*3 + //add edi, ebp + //pop edx + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_ALT); + + /* check for errors */ + //test eax, eax + //jne :error + IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); + + /* pop the stack. do not check the margins. + * Note that this is not a true macro - we don't bother to + * set ALT here because nothing will be using it. + */ + num_params++; + num_params *= 4; + //add edi, + if (num_params < SCHAR_MAX && num_params > SCHAR_MIN) + { + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG); + } else { + IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG); + } +} /************************************************* ************************************************* @@ -1329,6 +1498,12 @@ inline void WriteOp_Casetbl(JitWriter *jit) ************************************************* *************************************************/ +cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) +{ + /* :TODO: fill this out... */ + + return 0; +} jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) { @@ -1340,7 +1515,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) /* The actual offset is EIP relative. We need to relocate it. * Note that this assumes that we're pointing to the next op. */ - pcode_offs += jit->inputrel(); + pcode_offs += jit->get_inputpos(); } /* Offset must always be 1)positive and 2)less than the codesize */ assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize); @@ -1416,43 +1591,59 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) * so we can check the exact memory usage. */ data->codesize = plugin->pcode_size; + writer.data = data; writer.inbase = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; - data->rebase = (jitcode_t *)engine->BaseAlloc(plugin->pcode_size); + data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size); /* Jump back here for second pass */ jit_rewind: /* Initialize pass vars */ writer.inptr = writer.inbase; - data->jit_chkmargin_heap = 0; data->jit_verify_addr_eax = 0; data->jit_verify_addr_edx = 0; - data->jit_bounds = 0; /* Start writing the actual code */ data->jit_return = Write_Execute_Function(jit); - /* Write error checking routines in case they are needed */ + /* Write error checking routines that are jumped to */ if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EAX, true); + jitpos = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EAX); data->jit_verify_addr_eax = jitpos; - jitpos = jit->jit_curpos(); - Write_Check_VerifyAddr(jit, REG_EDX, true); + jitpos = jit->get_outputpos(); + Write_Check_VerifyAddr(jit, REG_EDX); data->jit_verify_addr_edx = jitpos; - - jitpos = jit->jit_curpos(); - Write_CheckMargin_Heap(jit); - data->jit_chkmargin_heap = jitpos; - - jitpos = jit->jit_curpos(); - Write_BoundsCheck(jit); - data->jit_bounds = jitpos; } + /* Write error codes we need */ + { + data->jit_error_divzero = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_DIVIDE_BY_ZERO); + + data->jit_error_stacklow = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_STACKLOW); + + data->jit_error_stackmin = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_STACKMIN); + + data->jit_error_bounds = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_ARRAY_BOUNDS); + + data->jit_error_memaccess = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_MEMACCESS); + + data->jit_error_heaplow = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_HEAPLOW); + + data->jit_error_heapmin = jit->get_outputpos(); + Write_SetError(jit, true, SP_ERR_HEAPMIN); + } + + /* Actual code generation! */ if (writer.outbase == NULL) { /******* @@ -1461,14 +1652,14 @@ jit_rewind: jitoffs_t pcode_offs; jitoffs_t native_offs; - for (; writer.inptr <= endptr;) + for (; writer.inptr < endptr;) { /* Store the native offset into the rebase memory. * This large chunk of memory lets us do an instant lookup * based on an original pcode offset. */ pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); - native_offs = jit->jit_curpos(); + native_offs = jit->get_outputpos(); *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; /* Now read the opcode and continue. */ @@ -1480,7 +1671,7 @@ jit_rewind: } /* the total codesize is now known! */ - uint32_t mem = writer.jit_curpos(); + uint32_t mem = writer.get_outputpos(); writer.outbase = (jitcode_t)engine->ExecAlloc(mem); writer.outptr = writer.outbase; /* go back for third pass */ @@ -1489,7 +1680,7 @@ jit_rewind: /******* * THIRD PASS - write opcode info *******/ - for (; writer.inptr <= endptr;) + for (; writer.inptr < endptr;) { op = (OPCODE)writer.read_cell(); switch (op) @@ -1630,7 +1821,7 @@ const char *JITX86::GetVMName() int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) { typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *); - CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; + CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; return fn(ctx, code_idx, result); } @@ -1652,6 +1843,7 @@ ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin) CompData *data = new CompData; data->plugin = plugin; + data->inline_level = JIT_INLINE_ERRORCHECKS; return data; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 13f63f7aa..ee0e0524e 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,28 +9,32 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) -#define STACK_MARGIN 16 +#define STACK_MARGIN 64 //8 parameters of safety, I guess class CompData : public ICompilation { public: CompData() : plugin(NULL), - debug(false), inline_level(3), checks(true), - rebase(NULL) + debug(false), inline_level(0), rebase(NULL) { }; public: sp_plugin_t *plugin; - jitcode_t *rebase; + jitcode_t rebase; jitoffs_t jit_return; jitoffs_t jit_verify_addr_eax; jitoffs_t jit_verify_addr_edx; - jitoffs_t jit_chkmargin_heap; - jitoffs_t jit_bounds; jitoffs_t jit_break; + jitoffs_t jit_sysreq_n; + jitoffs_t jit_error_bounds; + jitoffs_t jit_error_divzero; + jitoffs_t jit_error_stacklow; + jitoffs_t jit_error_stackmin; + jitoffs_t jit_error_memaccess; + jitoffs_t jit_error_heaplow; + jitoffs_t jit_error_heapmin; uint32_t codesize; int inline_level; - bool checks; bool debug; }; @@ -48,6 +52,7 @@ public: int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); }; +cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params); jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_REG_PRI REG_EAX @@ -65,6 +70,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false); #define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_STACKTOP 16 //relocated #define AMX_INFO_HEAPLOW 20 //not relocated +#define AMX_INFO_STACKTOP_U 24 //not relocated extern ISourcePawnEngine *engine; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 1bd339025..a218ff822 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -6,6 +6,8 @@ int OpAdvTable[OP_NUM_OPCODES]; +#define NUM_INFO_PARAMS 7 + jitoffs_t Write_Execute_Function(JitWriter *jit) { /** @@ -20,7 +22,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) * This is because we do not support resuming or sleeping! */ - //:TODO: FIX THIS FOR THE EBP AND EDI SWITCHING //push ebp //mov ebp, esp IA32_Push_Reg(jit, REG_EBP); @@ -33,9 +34,9 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EBX); - //sub esp, 4*6 - allocate info array + //sub esp, 4*n - reserve info array //mov esi, esp - save info pointer - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG); /* Initial memory setup */ @@ -45,7 +46,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) //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 + //mov ebp, [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); @@ -55,76 +56,73 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) 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 + //mov edi, [eax+] - get stack pointer + //add edi, ebp - relocate to data section + //mov ebx, edi - copy sp to frm IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); - IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); 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+] - copy memsize to temp var + //mov [esi+x], ecx - store unrelocated + //add ecx, ebp - relocate + //mov [esi+x], ecx - store relocated //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_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory)); + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U); + IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); 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 - //mov eax, [eax+] - get pri - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); + //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack) + //add ecx, [eax+] - add code base to index + IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3))); IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase)); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt)); - 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_Reg(jit, REG_ECX); /* if the code flow gets to here, there was a normal return */ - //mov ebp, [esi+8] - get retval pointer - //mov [ebp], eax - store retval from PRI + //mov ecx, [esi+8] - get retval pointer + //mov [ecx], eax - store retval from PRI //mov eax, SP_ERR_NONE - set no error - IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL); - IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL); + IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG); IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE); /* save where error checking/halting functions should go to */ - jitoffs_t offs_return; - CompData *data = (CompData *)jit->data; - if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) - { - /* We have to write code assume we're breaking out of a call */ - //jmp [past the next instruction] - //add esp, 4 - jitoffs_t offs = IA32_Jump_Imm8(jit, 0); - offs_return = jit->jit_curpos(); - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - IA32_Send_Jump8_Here(jit, offs); - } else { - offs_return = jit->jit_curpos(); - } + jitoffs_t offs_return = jit->get_outputpos(); + //mov esp, esi - restore stack pointer + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG); - /* _FOR NOW_ ... - * We are _not_ going to restore anything that was on the stack. - * This is a tiny, useless optimization based on the fact that - * BaseContext::Execute() automatically restores our values anyway. + /* _FOR NOW_ ... + * We are going to restore SP, HP, and FRM for now. This is for + * debugging only, to check for alignment errors. As such: + * :TODO: probably remove this. */ + //mov ecx, [esi+context] + //sub edi, ebp + //mov edx, [esi+heap] + //mov [ecx+sp], edi + //mov [ecx+hp], edx + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT); + IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp)); + IA32_Mov_Rm_Reg(jit, REG_ECX, REG_EDX, MOD_REG); - //add esp, 4*6 + //add esp, 4*NUM_INFO_PARAMS //pop ebx //pop edi //pop esi //pop ebp //ret - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG); + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG); IA32_Pop_Reg(jit, REG_EBX); IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_ESI); @@ -167,7 +165,7 @@ void Write_BreakDebug(JitWriter *jit) IA32_Return(jit); } -void Write_Error(JitWriter *jit, int error) +void Write_SetError(JitWriter *jit, bool always_inline, int error) { CompData *data = (CompData *)jit->data; @@ -182,22 +180,67 @@ void Write_Error(JitWriter *jit, int error) void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg) { //test reg, reg - //jnz :continue - //divzero: (write error) + //jz :error IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0); - if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) - { - //sub esp, 4 - correct stack for returning to non-inlined JIT - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - } - Write_Error(jit, SP_ERR_DIVIDE_BY_ZERO); - //continue: - IA32_Send_Jump8_Here(jit, jmp); - + IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero); } -//:TODO: FIX THIS FOR NEW EBP STUFF -void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) + +void Write_CheckHeap_Min(JitWriter *jit) +{ + /* Check if the stack went beyond the heap low. + * This usually means there was a compiler error. + * NOTE: Special optimization here. + * The heap low is always known ahead of time! :) + */ + CompData *data = (CompData *)jit->data; + //cmp [esi+info.heap], + //jb :error + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin); +} + +void Write_CheckHeap_Low(JitWriter *jit) +{ + /* Check if the heap is trying to grow beyond the stack. + */ + //mov ecx, [esi+info.heap] + //lea ecx, [ebp+ecx+STACK_MARGIN] + //cmp ecx, edi + //ja :error ; I think this is right + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow); +} + +void Write_CheckStack_Min(JitWriter *jit) +{ + /* Check if the stack went beyond the stack top + * This usually means there was a compiler error. + */ + //cmp edi, [esi+info.stacktop] + //jae :error + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin); +} + +void Write_CheckStack_Low(JitWriter *jit) +{ + /* Check if the stack went beyond the heap boundary. + * Unfortunately this one isn't as quick as the other check. + * The stack margin check is important for sysreq.n having space. + */ + //mov ecx, [esi+info.heap] + //lea ecx, [ebp+ecx+STACK_MARGIN] + //cmp edi, ecx + //jb :error ; I think this is right + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); + IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow); +} + +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg) { CompData *data = (CompData *)jit->data; @@ -205,182 +248,57 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall) * The old JIT did not. */ - if (!data->checks) - { - return; - } - bool call = false; if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) { /* If we're not in the initial generation phase, * Write a call to the actual routine instead. */ - if (!firstcall) + if ((reg == REG_EAX) && data->jit_verify_addr_eax) { jitoffs_t call = IA32_Call_Imm32(jit, 0); - if (reg == REG_EAX) - { - IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); - } else if (reg == REG_EDX) { - IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); - } + IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax); + return; + } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) { + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx); return; } call = true; - } else if (firstcall) { - /* Inline + initial gen == no code */ - return; } - //cmp reg, [stp] - //jae memaccess - //cmp reg, [hea] - //jb continue - //lea ecx, [reg+edi] - //cmp ecx, ebp - //jae continue - //memaccess: (write error) - //continue: - IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); + /** + * :TODO: If we can't find a nicer way of doing this, + * then scrap it on high optimizations. The second portion is not needed at all! + */ + + /* Part 1: Check if we're in the memory bounds */ + //cmp , [esi+info.stpu] + //jae :error + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP_U); + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess); + + /* Part 2: Check if we're in the invalid region between HP and SP */ + jitoffs_t jmp; + //cmp , [esi+info.heap] + //jb :continue + //lea ecx, [ebp+] + //cmp edi, ecx + //jb :error + //:continue IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0); - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_TMP, reg, AMX_REG_DAT, NOSCALE); - IA32_Cmp_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); - jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0); - IA32_Send_Jump8_Here(jit, jmp1); - Write_Error(jit, SP_ERR_MEMACCESS); - IA32_Send_Jump8_Here(jit, jmp2); - IA32_Send_Jump8_Here(jit, jmp3); + jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0); + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0); + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess); + IA32_Send_Jump8_Here(jit, jmp); + if (call) { IA32_Return(jit); } } -void Write_BoundsCheck(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS); - - /* :TODO: break out on high -O level? */ - - if (!always_inline) - { - if (data->jit_bounds) - { - /* just generate the call */ - //mov ecx, - //call - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit->read_cell()); - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, data->jit_bounds); - } else { - //cmp eax, 0 - //jl :err_bounds - //cmp eax, ecx - //jg :err_bounds - //ret - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //:TODO: make sure this is right order - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); - IA32_Return(jit); - IA32_Send_Jump8_Here(jit, jmp1); - IA32_Send_Jump8_Here(jit, jmp2); - Write_Error(jit, SP_ERR_ARRAY_BOUNDS); - } - } else { - //cmp eax, 0 - //jl :err_bounds - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0); - jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //cmp eax, - //jg :err_bounds - cell_t val = jit->read_cell(); - if (val < SCHAR_MAX && val > SCHAR_MIN) - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); - else - IA32_Cmp_Eax_Imm32(jit, val); - jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0); - //jmp :continue - jitoffs_t cont = IA32_Jump_Imm8(jit, 0); - //:err_bounds - IA32_Send_Jump8_Here(jit, jmp1); - IA32_Send_Jump8_Here(jit, jmp2); - Write_Error(jit, SP_ERR_ARRAY_BOUNDS); - //:continue - IA32_Send_Jump8_Here(jit, cont); - } -} - -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, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW); - jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0); - //lea ecx, [ebp+ecx+STACK_MARGIN] - //cmp ecx, edi - // jg :error_heaplow - //OR - // ret - IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN); - IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, 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. - */ - //cmp edi, [esi+stp] - //jle :continue - IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP); - jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0); - if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS)) - { - //sub esp, 4 - correct stack for returning to non-inlined JIT - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - } - Write_Error(jit, SP_ERR_STACKMIN); - //continue: - IA32_Send_Jump8_Here(jit, jmp); -} - void Macro_PushN_Addr(JitWriter *jit, int i) { //push eax @@ -404,6 +322,7 @@ void Macro_PushN_Addr(JitWriter *jit, int i) IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n); } while (n++ < i); + //:TODO: fix the case of this size > imm8! IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); IA32_Pop_Reg(jit, AMX_REG_PRI); } @@ -464,6 +383,83 @@ void Macro_PushN(JitWriter *jit, int i) IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG); } +void WriteOp_Sysreq_N_Function(JitWriter *jit) +{ + /* The big daddy of opcodes. + * eax - num_params + * ecx - native index + */ + CompData *data = (CompData *)jit->data; + + /* store the number of parameters on the stack */ + //mov [edi-4], eax + //sub edi, 4 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4); + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + + /* save registers we will need */ + //push eax ; num_params for stack popping + //push edx + IA32_Push_Reg(jit, REG_EAX); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* push some callback stuff */ + //push edi ; stack + //push ecx ; native index + IA32_Push_Reg(jit, AMX_REG_STK); + IA32_Push_Reg(jit, REG_ECX); + + /* Relocate stack, heap, frm information, then store back */ + //sub edi, ebp + //mov ecx, [esi+hea] + //mov eax, [esi+context] + //mov [eax+hp], ecx + //mov [eax+sp], edi + //mov ecx, [esi+frm] + //mov [eax+frm], ecx + IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG); + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); + + /* finally, push the last parameter and make the call */ + //push eax ; context + //mov eax, [eax+context] + //call NativeCallback + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback); + + /* restore what we damaged */ + //add esp, 4*3 + //add edi, ebp + //pop edx + //pop ecx ; num_params + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG); + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, REG_ECX); + + //Note: always safe, we're in a call + //test eax, eax + //jne :error + IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return); + + /* pop the AMX stack. do not check the margins. + * Note that this is not a true macro - we don't bother to + * set ALT here because nothing will be using it. + */ + //lea edi, [edi+ecx*4+4] + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4); + + //ret + IA32_Return(jit); +} + JITX86::JITX86() { memset(OpAdvTable, -1, sizeof(OpAdvTable)); @@ -643,5 +639,4 @@ JITX86::JITX86() OpAdvTable[OP_JLEQ] = -3; OpAdvTable[OP_JGRTR] = -3; OpAdvTable[OP_JGEQ] = -3; - } diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index c0b502e84..b5d192dc7 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -10,39 +10,41 @@ */ jitoffs_t Write_Execute_Function(JitWriter *jit); +/** + * Writes the Sysreq.n opcode as a function call. + */ +void WriteOp_Sysreq_N_Function(JitWriter *jit); + /** * Generates code to set an error state in the VM and return. - * Note that this should only be called from inside an error - * checking function. + * This is used for generating the error set points in the VM. */ -void Write_Error(JitWriter *jit, int error); +void Write_SetError(JitWriter *jit, bool always_inline, int error); /** - * Verifies an address by register. - * :TODO: optimize and make it look like the heap checkfunction! + * Checks the stacks for min and low errors. + * :TODO: Should a variation of this go in the pushN opcodes? */ -void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall); +void Write_CheckStack_Min(JitWriter *jit); +void Write_CheckStack_Low(JitWriter *jit); /** - * Verifies stack margins. + * Checks the heap for min and low errors. */ -void Write_CheckMargin_Stack(JitWriter *jit); +void Write_CheckHeap_Min(JitWriter *jit); +void Write_CheckHeap_Low(JitWriter *jit); -/** - * Verifies heap margins. +/** + * Verifies an address by register. The address must reside + * between DAT and HP and SP and STP. */ -void Write_CheckMargin_Heap(JitWriter *jit); +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg); /** * Checks for division by zero. */ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg); -/** - * Writes a bounds check. - */ -void Write_BoundsCheck(JitWriter *jit); - /** * Writes the break debug function. */ @@ -56,132 +58,147 @@ void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); void Macro_PushN(JitWriter *jit, int i); +/** + * Legend for Statuses: + * ****** *** ******** + * DONE -> code generation is done + * !GEN -> code generation is deliberate skipped because: + * (default): compiler does not generate + * DEPRECATED: this feature no longer exists/supported + * UNSUPPORTED: this opcode is not supported + * TODO: done in case needed + * VERIFIED -> code generation is checked as run-time working. prefixes: + * ! errors are not checked yet. + * - non-inline errors are not checked yet. + * ~ assumed checked because of related variation, but not actually checked + */ + typedef enum { OP_NONE, /* invalid opcode */ - OP_LOAD_PRI, //DONE - OP_LOAD_ALT, //DONE - OP_LOAD_S_PRI, //DONE - OP_LOAD_S_ALT, //DONE + OP_LOAD_PRI, //!VERIFIED + OP_LOAD_ALT, //~!VERIFIED (load.pri) + OP_LOAD_S_PRI, //VERIFIED + OP_LOAD_S_ALT, //VERIFIED OP_LREF_PRI, // !GEN :TODO: we will need this for dynarrays OP_LREF_ALT, // !GEN :TODO: we will need this for dynarrays - OP_LREF_S_PRI, //DONE - OP_LREF_S_ALT, //DONE - OP_LOAD_I, //DONE + OP_LREF_S_PRI, //VERIFIED + OP_LREF_S_ALT, //~VERIFIED (lref.s.pri) + OP_LOAD_I, //VERIFIED OP_LODB_I, // !GEN :TODO: - only used for pack access - drop support in compiler first - OP_CONST_PRI, //DONE - OP_CONST_ALT, //DONE - OP_ADDR_PRI, //DONE - OP_ADDR_ALT, //DONE - OP_STOR_PRI, //DONE - OP_STOR_ALT, //DONE - OP_STOR_S_PRI, //DONE - OP_STOR_S_ALT, //DONE - OP_SREF_PRI, //DONE - OP_SREF_ALT, //DONE - OP_SREF_S_PRI, // !GEN :TODO: we will need this for dynarrays - OP_SREF_S_ALT, // !GEN :TODO: we will need this for dynarrays - OP_STOR_I, //DONE + OP_CONST_PRI, //VERIFIED + OP_CONST_ALT, //~VERIFIED (const.pri) + OP_ADDR_PRI, //VERIFIED + OP_ADDR_ALT, //VERIFIED + OP_STOR_PRI, //VERIFIED + OP_STOR_ALT, //~VERIFIED (stor.pri) + OP_STOR_S_PRI, //VERIFIED + OP_STOR_S_ALT, //~VERIFIED (stor.s.pri) + OP_SREF_PRI, // !GEN :TODO: we will need this for dynarrays + OP_SREF_ALT, // !GEN :TODO: we will need this for dynarrays + OP_SREF_S_PRI, //VERIFIED + OP_SREF_S_ALT, //~VERIFIED (stor.s.alt) + OP_STOR_I, //VERIFIED OP_STRB_I, // !GEN :TODO: - only used for pack access, drop support in compiler first - OP_LIDX, //DONE + OP_LIDX, //VERIFIED OP_LIDX_B, //DONE - OP_IDXADDR, //DONE + OP_IDXADDR, //VERIFIED OP_IDXADDR_B, //DONE OP_ALIGN_PRI, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first OP_LCTRL, // !GEN OP_SCTRL, // !GEN OP_MOVE_PRI, //DONE - OP_MOVE_ALT, //DONE + OP_MOVE_ALT, //VERIFIED OP_XCHG, //DONE OP_PUSH_PRI, //DONE OP_PUSH_ALT, //DONE OP_PUSH_R, // !GEN DEPRECATED - OP_PUSH_C, //DONE + OP_PUSH_C, //VERIFIED OP_PUSH, //DONE - OP_PUSH_S, //DONE - OP_POP_PRI, //DONE - OP_POP_ALT, //DONE - OP_STACK, //DONE + OP_PUSH_S, //VERIFIED + OP_POP_PRI, //VERIFIED + OP_POP_ALT, //VERIFIED + OP_STACK, //VERIFIED OP_HEAP, //DONE - OP_PROC, //DONE + OP_PROC, //VERIFIED OP_RET, // !GEN - OP_RETN, //DONE - OP_CALL, //DONE + OP_RETN, //VERIFIED + OP_CALL, //VERIFIED OP_CALL_PRI, // !GEN - OP_JUMP, //DONE + OP_JUMP, //VERIFIED OP_JREL, // !GEN - OP_JZER, //DONE + OP_JZER, //VERIFIED OP_JNZ, //DONE - OP_JEQ, //DONE - OP_JNEQ, //DONE + OP_JEQ, //VERIFIED + OP_JNEQ, //VERIFIED OP_JLESS, // !GEN OP_JLEQ, // !GEN OP_JGRTR, // !GEN OP_JGEQ, // !GEN - OP_JSLESS, //DONE - OP_JSLEQ, //DONE - OP_JSGRTR, //DONE - OP_JSGEQ, //DONE - OP_SHL, //DONE - OP_SHR, //DONE - OP_SSHR, //DONE + OP_JSLESS, //VERIFIED + OP_JSLEQ, //VERIFIED + OP_JSGRTR, //VERIFIED + OP_JSGEQ, //VERIFIED + OP_SHL, //VERIFIED + OP_SHR, //VERIFIED (Note: operator >>>) + OP_SSHR, //VERIFIED (Note: operator >>) OP_SHL_C_PRI, //DONE OP_SHL_C_ALT, //DONE OP_SHR_C_PRI, //DONE OP_SHR_C_ALT, //DONE - OP_SMUL, //DONE + OP_SMUL, //VERIFIED OP_SDIV, //DONE - OP_SDIV_ALT, //DONE + OP_SDIV_ALT, //VERIFIED OP_UMUL, // !GEN OP_UDIV, // !GEN OP_UDIV_ALT, // !GEN - OP_ADD, //DONE + OP_ADD, //VERIFIED OP_SUB, //DONE - OP_SUB_ALT, //DONE - OP_AND, //DONE - OP_OR, //DONE - OP_XOR, //DONE - OP_NOT, //DONE - OP_NEG, //DONE - OP_INVERT, //DONE - OP_ADD_C, //DONE - OP_SMUL_C, //DONE - OP_ZERO_PRI, //DONE - OP_ZERO_ALT, //DONE - OP_ZERO, //DONE - OP_ZERO_S, //DONE + OP_SUB_ALT, //VERIFIED + OP_AND, //VERIFIED + OP_OR, //VERIFIED + OP_XOR, //VERIFIED + OP_NOT, //VERIFIED + OP_NEG, //VERIFIED + OP_INVERT, //VERIFIED + OP_ADD_C, //VERIFIED + OP_SMUL_C, //VERIFIED + OP_ZERO_PRI, //VERIFIED + OP_ZERO_ALT, //~VERIFIED + OP_ZERO, //VERIFIED + OP_ZERO_S, //VERIFIED OP_SIGN_PRI, //DONE OP_SIGN_ALT, //DONE - OP_EQ, //DONE - OP_NEQ, //DONE + OP_EQ, //VERIFIED + OP_NEQ, //VERIFIED OP_LESS, // !GEN OP_LEQ, // !GEN OP_GRTR, // !GEN OP_GEQ, // !GEN - OP_SLESS, //DONE - OP_SLEQ, //DONE - OP_SGRTR, //DONE - OP_SGEQ, //DONE + OP_SLESS, //VERIFIED + OP_SLEQ, //VERIFIED + OP_SGRTR, //VERIFIED + OP_SGEQ, //VERIFIED OP_EQ_C_PRI, //DONE OP_EQ_C_ALT, //DONE - OP_INC_PRI, //DONE - OP_INC_ALT, //DONE - OP_INC, //DONE - OP_INC_S, //DONE - OP_INC_I, //DONE - OP_DEC_PRI, //DONE - OP_DEC_ALT, //DONE - OP_DEC, //DONE - OP_DEC_S, //DONE - OP_DEC_I, //DONE + OP_INC_PRI, //VERIFIED + OP_INC_ALT, //~VERIFIED (inc.pri) + OP_INC, //VERIFIED + OP_INC_S, //VERIFIED + OP_INC_I, //VERIFIED + OP_DEC_PRI, //VERIFIED + OP_DEC_ALT, //~VERIFIED (dec.pri) + OP_DEC, //VERIFIED + OP_DEC_S, //VERIFIED + OP_DEC_I, //VERIFIED OP_MOVS, //DONE OP_CMPS, // !GEN - OP_FILL, //DONE + OP_FILL, //VERIFIED OP_HALT, //DONE - OP_BOUNDS, //DONE + OP_BOUNDS, //VERIFIED OP_SYSREQ_PRI, // !GEN - OP_SYSREQ_C, + OP_SYSREQ_C, // !GEN DEPRECATED OP_FILE, // !GEN DEPRECATED OP_LINE, // !GEN DEPRECATED OP_SYMBOL, // !GEN DEPRECATED @@ -189,32 +206,32 @@ typedef enum OP_JUMP_PRI, // !GEN OP_SWITCH, //DONE OP_CASETBL, //DONE - OP_SWAP_PRI, //DONE - OP_SWAP_ALT, //DONE - OP_PUSH_ADR, //DONE - OP_NOP, //DONE + OP_SWAP_PRI, //VERIFIED + OP_SWAP_ALT, //~VERIFIED (swap.alt) + OP_PUSH_ADR, //VERIFIED + OP_NOP, //VERIFIED (lol) OP_SYSREQ_N, OP_SYMTAG, // !GEN DEPRECATED OP_BREAK, //DONE - OP_PUSH2_C, //DONE - OP_PUSH2, //DONE - OP_PUSH2_S, //DONE - OP_PUSH2_ADR, //DONE - OP_PUSH3_C, //DONE - OP_PUSH3, //DONE - OP_PUSH3_S, //DONE - OP_PUSH3_ADR, //DONE - OP_PUSH4_C, //DONE - OP_PUSH4, //DONE - OP_PUSH4_S, //DONE - OP_PUSH4_ADR, //DONE - OP_PUSH5_C, //DONE - OP_PUSH5, //DONE - OP_PUSH5_S, //DONE - OP_PUSH5_ADR, //DONE - OP_LOAD_BOTH, //DONE - OP_LOAD_S_BOTH, //DONE - OP_CONST, //DONE + OP_PUSH2_C, //~VERIFIED (push3.c) + OP_PUSH2, //VERIFIED + OP_PUSH2_S, //VERIFIED + OP_PUSH2_ADR, //VERIFIED + OP_PUSH3_C, //VERIFIED + OP_PUSH3, //~VERIFIED (push2) + OP_PUSH3_S, //~VERIFIED (push2.s) + OP_PUSH3_ADR, //~VERIFIED (push2.adr) + OP_PUSH4_C, //~VERIFIED (push3.c) + OP_PUSH4, //~VERIFIED (push2) + OP_PUSH4_S, //~VERIFIED (push2.s) + OP_PUSH4_ADR, //~VERIFIED (push2.adr) + OP_PUSH5_C, //~VERIFIED (push3.c) + OP_PUSH5, //~VERIFIED (push2) + OP_PUSH5_S, //~VERIFIED (push2.s) + OP_PUSH5_ADR, //~VERIFIED (push2.adr) + OP_LOAD_BOTH, //VERIFIED + OP_LOAD_S_BOTH, //VERIFIED + OP_CONST, //VERIFIED OP_CONST_S, //DONE /* ----- */ OP_SYSREQ_D, // !GEN UNSUPPORT diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index f4b49b5a1..fde04a9d0 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -30,7 +30,7 @@ } case OP_PUSH3_C: { - WriteOp_Push3(jit); + WriteOp_Push3_C(jit); break; } case OP_PUSH4_C: @@ -350,12 +350,12 @@ } case OP_LREF_S_PRI: { - WriteOp_Lref_Pri(jit); + WriteOp_Lref_S_Pri(jit); break; } case OP_LREF_S_ALT: { - WriteOp_Lref_Alt(jit); + WriteOp_Lref_S_Alt(jit); break; } case OP_CONST_PRI: @@ -613,6 +613,16 @@ WriteOp_Jsless(jit); break; } + case OP_JSGRTR: + { + WriteOp_JsGrtr(jit); + break; + } + case OP_JSGEQ: + { + WriteOp_JsGeq(jit); + break; + } case OP_JSLEQ: { WriteOp_Jsleq(jit); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index e423b5967..0a733d0a4 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -117,6 +117,7 @@ #define IA32_POP_REG 0x58 // encoding is +r #define IA32_PUSH_REG 0x50 // encoding is +r #define IA32_PUSH_RM 0xFF // encoding is /6 +#define IA32_PUSH_IMM32 0x68 // encoding is #define IA32_REP 0xF3 // no extra encoding #define IA32_MOVSD 0xA5 // no extra encoding #define IA32_MOVSB 0xA4 // no extra encoding @@ -124,6 +125,8 @@ #define IA32_CLD 0xFC // no extra encoding #define IA32_PUSHAD 0x60 // no extra encoding #define IA32_POPAD 0x61 // no extra encoding +#define IA32_NOP 0x90 // no extra encoding +#define IA32_INT3 0xCC // no extra encoding inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -368,6 +371,13 @@ inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } +inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_SUB_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp8); +} + inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_RM_IMM8); @@ -475,7 +485,7 @@ inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit, { jit->write_ubyte(IA32_ADD_RM_IMM32); jit->write_ubyte(ia32_modrm(mode, 0, dest)); - jitoffs_t ptr = jit->jit_curpos(); + jitoffs_t ptr = jit->get_outputpos(); jit->write_int32(0); return ptr; } @@ -599,6 +609,12 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) jit->write_ubyte(IA32_PUSH_REG+reg); } +inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val) +{ + jit->write_ubyte(IA32_PUSH_IMM32); + jit->write_int32(val); +} + inline void IA32_Pushad(JitWriter *jit) { jit->write_ubyte(IA32_PUSHAD); @@ -633,6 +649,14 @@ inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp) +{ + jit->write_ubyte(IA32_MOV_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); + jit->write_byte(disp); +} + inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { jit->write_ubyte(IA32_MOV_REG_MEM); @@ -732,7 +756,7 @@ inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_ { jitoffs_t offs; jit->write_ubyte(IA32_MOV_REG_IMM+dest); - offs = jit->jit_curpos(); + offs = jit->get_outputpos(); jit->write_int32(num); return offs; } @@ -787,7 +811,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_ { jitoffs_t ptr; jit->write_ubyte(IA32_JCC_IMM+cond); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_byte(disp); return ptr; } @@ -796,7 +820,7 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_JMP_IMM32); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -805,7 +829,7 @@ inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_JMP_IMM8); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_byte(disp); return ptr; } @@ -815,7 +839,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int3 jitoffs_t ptr; jit->write_ubyte(IA32_JCC_IMM32_1); jit->write_ubyte(IA32_JCC_IMM32_2+cond); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -836,7 +860,7 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) { jitoffs_t ptr; jit->write_ubyte(IA32_CALL_IMM32); - ptr = jit->jit_curpos(); + ptr = jit->get_outputpos(); jit->write_int32(disp); return ptr; } @@ -878,7 +902,7 @@ inline void IA32_Jump_Imm32_Abs(JitWriter *jit, jitoffs_t target) { /* :TODO: this should work, but does it? */ jit->write_ubyte(IA32_JMP_IMM32); - IA32_Write_Jump32(jit, jit->jit_curpos(), target); + IA32_Write_Jump32(jit, jit->get_outputpos(), target); jit->outptr += 4; } @@ -887,19 +911,19 @@ inline void IA32_Jump_Cond_Imm32_Abs(JitWriter *jit, jit_uint8_t cond, jitoffs_t /* :TODO: this should work, but does it? */ jit->write_ubyte(IA32_JCC_IMM32_1); jit->write_ubyte(IA32_JCC_IMM32_2+cond); - IA32_Write_Jump32(jit, jit->jit_curpos(), target); + IA32_Write_Jump32(jit, jit->get_outputpos(), target); jit->outptr += 4; } inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->jit_curpos(); + jitoffs_t curptr = jit->get_outputpos(); IA32_Write_Jump8(jit, jmp, curptr); } inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp) { - jitoffs_t curptr = jit->jit_curpos(); + jitoffs_t curptr = jit->get_outputpos(); IA32_Write_Jump32(jit, jmp, curptr); }