Wrote the JIT execution function

Solidified some more code

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4079
This commit is contained in:
David Anderson 2006-09-20 07:07:49 +00:00
parent 3cdf54e7e9
commit 824beee935
7 changed files with 193 additions and 32 deletions

View File

@ -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();

View File

@ -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_

View File

@ -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+<offs>] - get heap pointer
//mov [esi+4], ecx - store heap into info pointer
//mov edi, [eax+<offs>] - 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+<offs>] - 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+<offs>] - add code base to index
//mov edx, [eax+<offs>] - get alt
//mov eax, [eax+<offs>] - 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;

View File

@ -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);

View File

@ -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 <imm8>
#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 <imm32>
#define IA32_JMP_IMM32 0xE9 // encoding is imm32
#define IA32_JMP_IMM8 0xEB // encoding is imm8
#define IA32_CALL_IMM32 0xE8 // relative call, <imm32>
#define IA32_CALL_RM 0xFF // encoding is /2
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
#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

View File

@ -189,10 +189,6 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\sp_vm_base.h"
>
</File>
<File
RelativePath="..\sp_vm_basecontext.h"
>
@ -319,6 +315,10 @@
RelativePath="..\..\include\sp_vm_api.h"
>
</File>
<File
RelativePath="..\..\include\sp_vm_base.h"
>
</File>
<File
RelativePath="..\..\include\sp_vm_context.h"
>

View File

@ -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)