1.1 --- a/sourcepawn/vm/jit/jit_helpers.h Wed Sep 20 07:07:49 2006 +0000
1.2 +++ b/sourcepawn/vm/jit/jit_helpers.h Wed Sep 20 08:44:21 2006 +0000
1.3 @@ -2,6 +2,7 @@
1.4 #define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
1.5
1.6 #include <sp_vm_types.h>
1.7 +#include <sp_vm_api.h>
1.8
1.9 #if defined HAVE_STDINT_H && !defined WIN32
1.10 #include <stdint.h>
1.11 @@ -70,6 +71,7 @@
1.12 cell_t *inptr; /* input pointer */
1.13 jitcode_t outbase; /* output pointer */
1.14 jitcode_t outptr; /* output base */
1.15 + SourcePawn::ICompilation *data; /* compiler live info */
1.16 };
1.17
1.18 #endif //_INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
2.1 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp Wed Sep 20 07:07:49 2006 +0000
2.2 +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp Wed Sep 20 08:44:21 2006 +0000
2.3 @@ -1,7 +1,6 @@
2.4 #include <string.h>
2.5 #include <stdlib.h>
2.6 #include "jit_x86.h"
2.7 -#include "..\jit_helpers.h"
2.8 #include "opcode_helpers.h"
2.9 #include "x86_macros.h"
2.10
2.11 @@ -1001,6 +1000,13 @@
2.12 }
2.13 }
2.14
2.15 +inline void WriteOp_Load_I(JitWriter *jit)
2.16 +{
2.17 + //mov eax, [edi+eax]
2.18 + Write_Check_VerifyAddr(jit, REG_EAX, false);
2.19 + IA32_Mov_Reg_Rm_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
2.20 +}
2.21 +
2.22
2.23 /*************************************************
2.24 *************************************************
2.25 @@ -1074,7 +1080,6 @@
2.26 JitWriter writer;
2.27 JitWriter *jit = &writer;
2.28 cell_t *endptr = (cell_t *)(end_cip);
2.29 - jitoffs_t jit_return;
2.30
2.31 /* Initial code is written "blank,"
2.32 * so we can check the exact memory usage.
2.33 @@ -1085,16 +1090,17 @@
2.34
2.35 /* Get inlining level */
2.36 int inline_level = data->inline_level;
2.37 - bool never_inline = false;
2.38 -
2.39 - if (inline_level == 0)
2.40 - {
2.41 - never_inline = true;
2.42 - }
2.43
2.44 //:TODO: Jump back here once finished!
2.45 +
2.46 /* Start writing the actual code */
2.47 - jit_return = Write_Execute_Function(jit, never_inline);
2.48 + data->jit_return = Write_Execute_Function(jit);
2.49 +
2.50 + /* Write error checking routines in case they are needed */
2.51 + data->jit_verify_addr_eax = jit->jit_curpos();
2.52 + Write_Check_VerifyAddr(jit, REG_EAX, true);
2.53 + data->jit_verify_addr_edx = jit->jit_curpos();
2.54 + Write_Check_VerifyAddr(jit, REG_EDX, true);
2.55
2.56 for (; writer.inptr <= endptr;)
2.57 {
2.58 @@ -1656,6 +1662,11 @@
2.59 WriteOp_Const_S(jit);
2.60 break;
2.61 }
2.62 + case OP_LOAD_I:
2.63 + {
2.64 + WriteOp_Load_I(jit);
2.65 + break;
2.66 + }
2.67 default:
2.68 {
2.69 AbortCompilation(co);
3.1 --- a/sourcepawn/vm/jit/x86/jit_x86.h Wed Sep 20 07:07:49 2006 +0000
3.2 +++ b/sourcepawn/vm/jit/x86/jit_x86.h Wed Sep 20 08:44:21 2006 +0000
3.3 @@ -3,17 +3,24 @@
3.4
3.5 #include <sp_vm_types.h>
3.6 #include <sp_vm_api.h>
3.7 +#include "..\jit_helpers.h"
3.8
3.9 using namespace SourcePawn;
3.10
3.11 +#define JIT_INLINE_ERRORCHECKS (1<<0)
3.12 +#define JIT_INLINE_NATIVES (1<<1)
3.13 +
3.14 class CompData : public ICompilation
3.15 {
3.16 public:
3.17 - CompData() : plugin(NULL), debug(false), inline_level(2)
3.18 + CompData() : plugin(NULL), debug(false), inline_level(3)
3.19 {
3.20 };
3.21 public:
3.22 sp_plugin_t *plugin;
3.23 + jitoffs_t jit_return;
3.24 + jitoffs_t jit_verify_addr_eax;
3.25 + jitoffs_t jit_verify_addr_edx;
3.26 int inline_level;
3.27 bool debug;
3.28 };
3.29 @@ -44,5 +51,6 @@
3.30 #define AMX_INFO_HEAP 4
3.31 #define AMX_INFO_RETVAL 8
3.32 #define AMX_INFO_CONTEXT 12
3.33 +#define AMX_INFO_STACKTOP 16
3.34
3.35 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
4.1 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp Wed Sep 20 07:07:49 2006 +0000
4.2 +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp Wed Sep 20 08:44:21 2006 +0000
4.3 @@ -9,19 +9,6 @@
4.4 jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
4.5 {
4.6 /**
4.7 - * The state expected by our plugin is:
4.8 - * #define AMX_REG_PRI REG_EAX (done)
4.9 - #define AMX_REG_ALT REG_EDX (done)
4.10 - #define AMX_REG_STK REG_EBP (done)
4.11 - #define AMX_REG_DAT REG_EDI (done)
4.12 - #define AMX_REG_TMP REG_ECX (nothing)
4.13 - #define AMX_REG_INFO REG_ESI (done)
4.14 - #define AMX_REG_FRM REG_EBX (done)
4.15 - #define AMX_INFO_FRM AMX_REG_INFO (done)
4.16 - #define AMX_INFO_HEAP 4 (done)
4.17 - #define AMX_INFO_RETVAL 8 (done)
4.18 - #define AMX_INFO_CONTEXT 12 (done)
4.19 - *
4.20 * The variables we're passed in:
4.21 * sp_context_t *ctx, uint32_t code_idx, cell_t *result
4.22 */
4.23 @@ -45,7 +32,7 @@
4.24 IA32_Push_Reg(jit, REG_EDI);
4.25 IA32_Push_Reg(jit, REG_EBX);
4.26
4.27 - //sub esp, 4*4 - allocate info array
4.28 + //sub esp, 4*5 - allocate info array
4.29 //mov esi, esp - save info pointer
4.30 IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
4.31 IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
4.32 @@ -69,13 +56,21 @@
4.33 //mov ebp, [eax+<offs>] - get stack pointer
4.34 //add ebp, edi - relocate to data section
4.35 //mov ebx, ebp - copy sp to frm
4.36 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
4.37 + IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
4.38 + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
4.39 +
4.40 + //mov ecx, edi - copy base of data to temp var
4.41 + //add ecx, [eax+<offs>] - add memsize to get stack top
4.42 + //mov [esi+16], ecx - store stack top into info pointer
4.43 + IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG);
4.44 + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
4.45 + IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_STACKTOP);
4.46 +
4.47 //mov ecx, [ebp+12] - get code index
4.48 //add ecx, [eax+<offs>] - add code base to index
4.49 //mov edx, [eax+<offs>] - get alt
4.50 //mov eax, [eax+<offs>] - get pri
4.51 - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
4.52 - IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
4.53 - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
4.54 IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12);
4.55 IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base));
4.56 IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt));
4.57 @@ -94,9 +89,10 @@
4.58 IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG);
4.59 IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE);
4.60
4.61 - /* where error checking/return functions should go to */
4.62 + /* save where error checking/halting functions should go to */
4.63 jitoffs_t offs_return;
4.64 - if (never_inline)
4.65 + CompData *data = (CompData *)jit->data;
4.66 + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
4.67 {
4.68 /* We have to write code assume we're breaking out of a call */
4.69 //jmp [past the next instruction]
4.70 @@ -121,7 +117,7 @@
4.71 //pop esi
4.72 //pop ebp
4.73 //ret
4.74 - IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
4.75 + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*5, MOD_REG);
4.76 IA32_Pop_Reg(jit, REG_EBX);
4.77 IA32_Pop_Reg(jit, REG_EDI);
4.78 IA32_Pop_Reg(jit, REG_ESI);
4.79 @@ -131,6 +127,75 @@
4.80 return offs_return;
4.81 }
4.82
4.83 +void Write_Error(JitWriter *jit, int error)
4.84 +{
4.85 + CompData *data = (CompData *)jit->data;
4.86 +
4.87 + /* These are so small that we always inline them! */
4.88 + //mov eax, <error>
4.89 + //jmp [...jit_return]
4.90 + IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
4.91 + jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
4.92 + IA32_Write_Jump32(jit, jmp, data->jit_return);
4.93 +}
4.94 +
4.95 +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall)
4.96 +{
4.97 + CompData *data = (CompData *)jit->data;
4.98 +
4.99 + /* :TODO: Should this be checking for below heaplow?
4.100 + * The old JIT did not.
4.101 + */
4.102 +
4.103 + bool call = false;
4.104 + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
4.105 + {
4.106 + /* If we're not in the initial generation phase,
4.107 + * Write a call to the actual routine instead.
4.108 + */
4.109 + if (!firstcall)
4.110 + {
4.111 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
4.112 + if (reg == REG_EAX)
4.113 + {
4.114 + IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
4.115 + } else if (reg == REG_EDX) {
4.116 + IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
4.117 + }
4.118 + return;
4.119 + }
4.120 + call = true;
4.121 + } else if (firstcall) {
4.122 + /* Inline + initial gen == no code */
4.123 + return;
4.124 + }
4.125 +
4.126 + //cmp reg, [stp]
4.127 + //jae memaccess
4.128 + //cmp reg, [hea]
4.129 + //jb continue
4.130 + //lea ecx, [reg+edi]
4.131 + //cmp ecx, ebp
4.132 + //jae continue
4.133 + //memaccess: (write error)
4.134 + //continue:
4.135 + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP);
4.136 + jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
4.137 + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
4.138 + jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
4.139 + IA32_Lea_DispRegReg(jit, REG_ECX, reg, REG_EDI);
4.140 + IA32_Cmp_Rm_Reg(jit, REG_ECX, AMX_REG_STK, MOD_REG);
4.141 + jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
4.142 + IA32_Send_Jump8_Here(jit, jmp1);
4.143 + Write_Error(jit, SP_ERR_MEMACCESS);
4.144 + IA32_Send_Jump8_Here(jit, jmp2);
4.145 + IA32_Send_Jump8_Here(jit, jmp3);
4.146 + if (call)
4.147 + {
4.148 + IA32_Return(jit);
4.149 + }
4.150 +}
4.151 +
4.152 void Macro_PushN_Addr(JitWriter *jit, int i)
4.153 {
4.154 //push eax
5.1 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h Wed Sep 20 07:07:49 2006 +0000
5.2 +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h Wed Sep 20 08:44:21 2006 +0000
5.3 @@ -7,11 +7,20 @@
5.4 * This outputs the execution function for a plugin.
5.5 * It also returns the 'return' offset, which is used for
5.6 * breaking out of the JIT during runtime.
5.7 - *
5.8 - * If 'never_inline' is true, it outputs slightly different code used for
5.9 - * inlining the error checking routines.
5.10 */
5.11 -jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline);
5.12 +jitoffs_t Write_Execute_Function(JitWriter *jit);
5.13 +
5.14 +/**
5.15 + * Generates code to set an error state in the VM and return.
5.16 + * Note that this should only be called from inside an error
5.17 + * checking function.
5.18 + */
5.19 +void Write_Error(JitWriter *jit, int error);
5.20 +
5.21 +/**
5.22 + * Verifies an address by register.
5.23 + */
5.24 +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall);
5.25
5.26 /**
5.27 * These are for writing the PushN opcodes.
5.28 @@ -32,7 +41,7 @@
5.29 OP_LREF_ALT, //DONE
5.30 OP_LREF_S_PRI, //DONE
5.31 OP_LREF_S_ALT, //DONE
5.32 - OP_LOAD_I,
5.33 + OP_LOAD_I, //DONE
5.34 OP_LODB_I,
5.35 OP_CONST_PRI, //DONE
5.36 OP_CONST_ALT, //DONE
6.1 --- a/sourcepawn/vm/jit/x86/x86_macros.h Wed Sep 20 07:07:49 2006 +0000
6.2 +++ b/sourcepawn/vm/jit/x86/x86_macros.h Wed Sep 20 08:44:21 2006 +0000
6.3 @@ -97,6 +97,7 @@
6.4 #define IA32_SHL_RM_CL 0xD3 // encoding is /4
6.5 #define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 <ib>
6.6 #define IA32_CMP_RM_REG 0x39 // encoding is /r
6.7 +#define IA32_CMP_REG_RM 0x3B // encoding is /r
6.8 #define IA32_SETCC_RM8_1 0x0F // opcode part 1
6.9 #define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits)
6.10 #define IA32_XCHG_EAX_REG 0x90 // encoding is +r
6.11 @@ -498,8 +499,16 @@
6.12 jit->write_byte(val);
6.13 }
6.14
6.15 +inline void IA32_Lea_DispRegReg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t dispreg)
6.16 +{
6.17 + jit->write_ubyte(IA32_LEA_REG_MEM);
6.18 + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
6.19 + jit->write_ubyte(ia32_sib(NOSCALE, dispreg, src_base));
6.20 +}
6.21 +
6.22 inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val)
6.23 {
6.24 + /* :TODO: - why does this take in src_base? */
6.25 jit->write_ubyte(IA32_LEA_REG_MEM);
6.26 jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, MOD_MEM_REG));
6.27 jit->write_byte(val);
6.28 @@ -507,6 +516,7 @@
6.29
6.30 inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
6.31 {
6.32 + /* :TODO: - why does this take in src_base? */
6.33 jit->write_ubyte(IA32_LEA_REG_MEM);
6.34 jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, MOD_MEM_REG));
6.35 jit->write_int32(val);
6.36 @@ -709,12 +719,31 @@
6.37 jit->outptr = oldptr;
6.38 }
6.39
6.40 +inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target)
6.41 +{
6.42 + //save old ptr
6.43 + jitcode_t oldptr = jit->outptr;
6.44 + //get relative difference
6.45 + jit_int32_t diff = (target - (jmp + 1));
6.46 + //overwrite old value
6.47 + jit->outptr = jit->outbase + jmp;
6.48 + jit->write_int32(diff);
6.49 + //restore old ptr
6.50 + jit->outptr = oldptr;
6.51 +}
6.52 +
6.53 inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp)
6.54 {
6.55 jitoffs_t curptr = jit->jit_curpos();
6.56 IA32_Write_Jump8(jit, jmp, curptr);
6.57 }
6.58
6.59 +inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp)
6.60 +{
6.61 + jitoffs_t curptr = jit->jit_curpos();
6.62 + IA32_Write_Jump32(jit, jmp, curptr);
6.63 +}
6.64 +
6.65 inline void IA32_Return(JitWriter *jit)
6.66 {
6.67 jit->write_ubyte(IA32_RET);
6.68 @@ -732,6 +761,13 @@
6.69 jit->write_ubyte(ia32_modrm(mode, src, dest));
6.70 }
6.71
6.72 +inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8)
6.73 +{
6.74 + jit->write_ubyte(IA32_CMP_REG_RM);
6.75 + jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2));
6.76 + jit->write_byte(disp8);
6.77 +}
6.78 +
6.79 inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8)
6.80 {
6.81 jit->write_ubyte(IA32_CMP_RM_IMM8);