diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index 693890d5..ca58068b 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -830,7 +830,6 @@ inline void WriteOp_Pop_Pri(JitWriter *jit) //add ebp, 4 IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - } inline void WriteOp_Pop_Alt(JitWriter *jit) @@ -1049,16 +1048,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) } else if (op_c == -1) { switch (op) { - case OP_SYSREQ_C: - case OP_SYSREQ_PRI: - case OP_SYSREQ_N: - { - if (!data->always_inline) - { - reloc_count++; - } - break; - } case OP_CASETBL: { ucell_t num = *(ucell_t *)cip; @@ -1083,14 +1072,30 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err) *********************************************/ JitWriter writer; + JitWriter *jit = &writer; + cell_t *endptr = (cell_t *)(end_cip); + jitoffs_t jit_return; + /* Initial code is written "blank," + * so we can check the exact memory usage. + */ writer.inptr = (cell_t *)code; writer.outptr = NULL; writer.outbase = NULL; -//redo_pass: - cell_t *endptr = (cell_t *)(end_cip); - JitWriter *jit = &writer; + /* Get inlining level */ + int inline_level = data->inline_level; + bool never_inline = false; + + if (inline_level == 0) + { + never_inline = true; + } + +//:TODO: Jump back here once finished! + /* Start writing the actual code */ + jit_return = Write_Execute_Function(jit, never_inline); + for (; writer.inptr <= endptr;) { op = (OPCODE)writer.read_cell(); diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 7fa56ce2..b3ba2e8d 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -9,12 +9,12 @@ using namespace SourcePawn; class CompData : public ICompilation { public: - CompData() : plugin(NULL), debug(false), always_inline(true) + CompData() : plugin(NULL), debug(false), inline_level(2) { }; public: sp_plugin_t *plugin; - bool always_inline; + int inline_level; bool debug; }; @@ -43,5 +43,6 @@ public: #define AMX_INFO_FRM AMX_REG_INFO #define AMX_INFO_HEAP 4 #define AMX_INFO_RETVAL 8 +#define AMX_INFO_CONTEXT 12 #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 012f3a05..43e39e77 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -6,26 +6,129 @@ int OpAdvTable[OP_NUM_OPCODES]; -void Write_Prologue(JitWriter *jit) +jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline) { /** * The state expected by our plugin is: - * #define AMX_REG_PRI REG_EAX - #define AMX_REG_ALT REG_EDX - #define AMX_REG_STK REG_EBP - #define AMX_REG_DAT REG_EDI - #define AMX_REG_TMP REG_ECX - #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 12 + * #define AMX_REG_PRI REG_EAX (done) + #define AMX_REG_ALT REG_EDX (done) + #define AMX_REG_STK REG_EBP (done) + #define AMX_REG_DAT REG_EDI (done) + #define AMX_REG_TMP REG_ECX (nothing) + #define AMX_REG_INFO REG_ESI (done) + #define AMX_REG_FRM REG_EBX (done) + #define AMX_INFO_FRM AMX_REG_INFO (done) + #define AMX_INFO_HEAP 4 (done) + #define AMX_INFO_RETVAL 8 (done) + #define AMX_INFO_CONTEXT 12 (done) * * The variables we're passed in: * sp_context_t *ctx, uint32_t code_idx, cell_t *result */ + /** + * !NOTE! + * Currently, we do not accept ctx->frm as the new frame pointer. + * Instead, we copy the frame from the stack pointer. + * This is because we do not support resuming or sleeping! + */ + //push ebp + //mov ebp, esp + IA32_Push_Reg(jit, REG_EBP); + IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG); + + //push esi + //push edi + //push ebx + IA32_Push_Reg(jit, REG_ESI); + IA32_Push_Reg(jit, REG_EDI); + IA32_Push_Reg(jit, REG_EBX); + + //sub esp, 4*4 - allocate info array + //mov esi, esp - save info pointer + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, 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); + + //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, 8); + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, 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_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data)); + + //mov ebp, [eax+] - get stack pointer + //add ebp, edi - relocate to data section + //mov ebx, ebp - copy sp to frm + //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, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp)); + 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); + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12); + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base)); + 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_Rm(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 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_Imm32(jit, REG_EAX, SP_ERR_NONE); + + /* where error checking/return functions should go to */ + jitoffs_t offs_return; + if (never_inline) + { + /* 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(); + } + + /* _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. + */ + + //add esp, 4*4 + //pop ebx + //pop edi + //pop esi + //pop ebp + //ret + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG); + IA32_Pop_Reg(jit, REG_EBX); + IA32_Pop_Reg(jit, REG_EDI); + IA32_Pop_Reg(jit, REG_ESI); + IA32_Pop_Reg(jit, REG_EBP); + IA32_Return(jit); + + return offs_return; } void Macro_PushN_Addr(JitWriter *jit, int i) @@ -142,6 +245,7 @@ JITX86::JITX86() OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2; OpAdvTable[OP_CONST] = sizeof(cell_t)*2; OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2; + OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2; /* instructions with 1 parameter */ OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t); @@ -199,6 +303,7 @@ JITX86::JITX86() OpAdvTable[OP_BOUNDS] = sizeof(cell_t); OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t); OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t); + OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t); /* instructions with 0 parameters */ OpAdvTable[OP_LOAD_I] = 0; @@ -261,6 +366,7 @@ JITX86::JITX86() OpAdvTable[OP_BREAK] = 0; OpAdvTable[OP_HEAP_PRI] = 0; OpAdvTable[OP_POP_HEAP_PRI] = 0; + OpAdvTable[OP_SYSREQ_PRI] = 0; /* opcodes that need relocation */ OpAdvTable[OP_CALL] = -2; diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index bfd86db9..64a753c6 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -3,6 +3,19 @@ #include "..\jit_helpers.h" +/** + * This outputs the execution function for a plugin. + * It also returns the 'return' offset, which is used for + * breaking out of the JIT during runtime. + * + * If 'never_inline' is true, it outputs slightly different code used for + * inlining the error checking routines. + */ +jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline); + +/** + * These are for writing the PushN opcodes. + */ void Macro_PushN_Addr(JitWriter *jit, int i); void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index 45ba5d8b..7d0d5a0a 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -53,6 +53,7 @@ #define IA32_XOR_RM_IMM32 0x81 // encoding is /6 #define IA32_XOR_RM_IMM8 0x83 // encoding is /6 #define IA32_ADD_RM_REG 0x01 // encoding is /r +#define IA32_ADD_REG_RM 0x03 // encoding is /r #define IA32_ADD_RM_IMM32 0x81 // encoding is /0 #define IA32_ADD_RM_IMM8 0x83 // encoding is /0 #define IA32_ADD_EAX_IMM32 0x05 // no extra encoding @@ -60,7 +61,9 @@ #define IA32_SUB_RM_IMM8 0x83 // encoding is /5 #define IA32_SUB_RM_IMM32 0x81 // encoding is /5 #define IA32_JMP_IMM32 0xE9 // encoding is imm32 +#define IA32_JMP_IMM8 0xEB // encoding is imm8 #define IA32_CALL_IMM32 0xE8 // relative call, +#define IA32_CALL_RM 0xFF // encoding is /2 #define IA32_MOV_REG_IMM 0xB8 // encoding is +r #define IA32_MOV_RM_REG 0x89 // encoding is /r #define IA32_MOV_REG_MEM 0x8B // encoding is /r @@ -385,6 +388,13 @@ inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp); } +inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->write_ubyte(IA32_ADD_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); + jit->write_byte(disp); +} + inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t val, @@ -652,6 +662,15 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } +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(); + jit->write_byte(disp); + return ptr; +} + inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp) { jitoffs_t ptr; @@ -671,6 +690,12 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } +inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg) +{ + jit->write_ubyte(IA32_CALL_RM); + jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg)); +} + inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) { //save old ptr diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj index 4e53d0b5..3bd93d34 100644 --- a/sourcepawn/vm/msvc8/vm.vcproj +++ b/sourcepawn/vm/msvc8/vm.vcproj @@ -189,10 +189,6 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - @@ -319,6 +315,10 @@ RelativePath="..\..\include\sp_vm_api.h" > + + diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp index bc38cc82..d64680f1 100644 --- a/sourcepawn/vm/sp_vm_basecontext.cpp +++ b/sourcepawn/vm/sp_vm_basecontext.cpp @@ -58,7 +58,18 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result) return err; } - return vm->ContextExecute(ctx, pubfunc->offs, result); + PushCell(ctx->pushcount); + ctx->pushcount = 0; + + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + + err = vm->ContextExecute(ctx, pubfunc->offs, result); + + ctx->sp = save_sp; + ctx->hp = save_hp; + + return err; } int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)