Landed sourcepawn-1.2. The big changes:

1) JIT compilation/optimization now occurs per-function, and only when functions are first used.  We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT).  This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive.  If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.

2) I've removed debug mode.  We always show full backtraces now, as there was a very cheap way to implement this which really cleaned up everything.  This is great for a number of reasons -- there's less code, the JIT is better designed, we don't need to relocate debug tables, and best of all we no longer have to tell users to enable debug mode at their own expense.

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402459
This commit is contained in:
David Anderson
2008-08-15 05:22:26 +00:00
parent 95aca7b61b
commit 7875fe1acd
49 changed files with 3475 additions and 1724 deletions
File diff suppressed because it is too large Load Diff
+60 -24
View File
@@ -34,9 +34,11 @@
#include <sp_vm_types.h>
#include <sp_vm_api.h>
#include <jit_helpers.h>
#include "../jit_shared.h"
#include "../BaseRuntime.h"
#include <KeCodeAllocator.h>
#include "jit_helpers.h"
#include "jit_shared.h"
#include "BaseRuntime.h"
#include "jit_function.h"
using namespace SourcePawn;
@@ -84,12 +86,27 @@ struct floattbl_t
unsigned int index;
};
struct call_thunk_t
{
jitoffs_t patch_addr;
cell_t pcode_offs;
jitoffs_t thunk_addr;
};
class CompData : public ICompilation
{
public:
CompData() : plugin(NULL),
debug(false), profile(0), inline_level(0), rebase(NULL),
error_set(SP_ERROR_NONE), func_idx(0)
CompData()
: runtime(NULL),
plugin(NULL),
rebase(NULL),
jit_float_table(NULL),
profile(0),
inline_level(0),
error_set(SP_ERROR_NONE),
num_thunks(0),
max_thunks(0),
thunks(NULL)
{
};
bool SetOption(const char *key, const char *val);
@@ -98,18 +115,15 @@ public:
public:
BaseRuntime *runtime; /* runtime handle */
sp_plugin_t *plugin; /* plugin handle */
bool debug; /* whether to compile debug mode */
uint8_t *rebase; /* relocation map */
floattbl_t *jit_float_table;
cell_t cur_func; /* current func pcode offset */
/* Options */
int profile; /* profiling flags */
int inline_level; /* inline optimization level */
jitcode_t rebase; /* relocation map */
/* Per-compilation properties */
int error_set; /* error code to halt process */
unsigned int func_idx; /* current function index */
jitoffs_t jit_return; /* point in main call to return to */
jitoffs_t jit_verify_addr_eax;
jitoffs_t jit_verify_addr_edx;
jitoffs_t jit_break; /* call to op.break */
jitoffs_t jit_sysreq_n; /* call version of op.sysreq.n */
jitoffs_t jit_genarray; /* call to genarray intrinsic */
jitoffs_t jit_error_bounds;
jitoffs_t jit_error_divzero;
jitoffs_t jit_error_stacklow;
@@ -117,32 +131,47 @@ public:
jitoffs_t jit_error_memaccess;
jitoffs_t jit_error_heaplow;
jitoffs_t jit_error_heapmin;
jitoffs_t jit_error_array_too_big;
jitoffs_t jit_extern_error; /* returning generic error */
jitoffs_t jit_sysreq_c; /* old version! */
jitoffs_t jit_rounding_table;
floattbl_t *jit_float_table;
uint32_t codesize; /* total codesize */
uint32_t num_thunks; /* number of thunks needed */
uint32_t max_thunks; /* maximum number of thunks */
call_thunk_t *thunks; /* thunk array */
};
class JITX86
{
public:
JITX86();
public:
bool InitializeJIT();
void ShutdownJIT();
ICompilation *StartCompilation(BaseRuntime *runtime);
ICompilation *StartCompilation();
bool Compile(ICompilation *co, BaseRuntime *runtime, int *err);
void FreePluginVars(sp_plugin_t *pl);
void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
void FreeContextVars(sp_context_t *ctx);
int ContextExecute(sp_plugin_t *pl, sp_context_t *ctx, uint32_t code_idx, cell_t *result);
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
JitFunction *CompileFunction(BaseRuntime *runtime, cell_t pcode_offs, int *err);
ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT);
int InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result);
public:
void *GetGenArrayIntrinsic();
void *GetReturnPoint();
void *GetRoundingTable();
void *AllocCode(size_t size);
void FreeCode(void *code);
private:
void *m_pJitEntry; /* Entry function */
void *m_pJitReturn; /* Return point for errors */
int m_RoundTable[3]; /* [-1, 0, 1] rounding table */
void *m_pJitGenArray; /* Generates an array */
};
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
uint32_t FuncLookup(CompData *data, cell_t pcode_offs);
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
void *CompileThunk(BaseRuntime *runtime, cell_t pcode_ffs, void *jmploc_addr);
#define AMX_REG_PRI REG_EAX
#define AMX_REG_ALT REG_EDX
@@ -152,13 +181,20 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
#define AMX_REG_INFO REG_ESI
#define AMX_REG_FRM REG_EBX
#define AMX_NUM_INFO_VARS 9
#define AMX_INFO_FRM AMX_REG_INFO //not relocated
#define AMX_INFO_FRAME 0 //(same thing as above)
#define AMX_INFO_HEAP 4 //not relocated
#define AMX_INFO_RETVAL 8 //physical
#define AMX_INFO_CONTEXT 12 //physical
#define AMX_INFO_STACKTOP 16 //relocated
#define AMX_INFO_CIP 20 //pcode CIP
#define AMX_INFO_DATASIZE 24 //plugin->data_size
#define AMX_INFO_MEMORY 28 //plugin->memory
#define AMX_INFO_NSTACK 32 //native stack
extern JITX86 g_Jit1;
extern Knight::KeCodeCache *g_pCodeCache;
extern JITX86 g_Jit;
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
+51 -257
View File
@@ -36,14 +36,11 @@
#include "opcode_helpers.h"
#include "x86_macros.h"
#define NUM_INFO_PARAMS 5
jitoffs_t Write_Execute_Function(JitWriter *jit)
{
CompData *co = (CompData *)jit->data;
/**
* The variables we're passed in:
* sp_context_t *ctx, uint32_t code_idx, cell_t *result
* void *vars[], void *entry_func
*/
/**
@@ -65,97 +62,58 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
IA32_Push_Reg(jit, REG_EDI);
IA32_Push_Reg(jit, REG_EBX);
//sub esp, 4*n - reserve info array
//mov esi, esp - save info pointer
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);
/* Prep us for doing the real work */
//mov esi, [ebp+param0] ;get vars
//mov ecx, [ebp+param1] ;get entry addr
//mov eax, [esi+MEMORY] ;get memory base
//mov edx, [esi+CONTEXT] ;get context
IA32_Mov_Reg_Rm_Disp8(jit, REG_ESI, REG_EBP, 8 + 4*0);
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 8 + 4*1);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_ESI, AMX_INFO_MEMORY);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_CONTEXT);
/* Initial memory setup */
//mov eax, [ebp+16] - get result pointer
//mov [esi+8], eax - store into info pointer
//mov eax, [ebp+8] - get context
//mov [esi+12], eax - store context into info pointer
//mov ecx, [eax+<offs>] - get heap pointer
//mov [esi+4], ecx - store heap into info pointer
//mov ebp, <addr> - get data pointer
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
IA32_Mov_Reg_Imm32(jit, AMX_REG_DAT, jit_int32_t(co->plugin->memory));
/* Frame setup */
//mov edi, [eax+<offs>] - 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, 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, [eax+<offs>] - copy memsize to temp var
//add ecx, ebp - relocate
//mov [esi+x], ecx - store relocated
IA32_Mov_Reg_Imm32(jit, REG_ECX, co->plugin->mem_size);
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);
/* Remaining needed vars */
//mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
//push eax
//mov eax, <addr of addr of code>
//mov eax, [eax]
//add ecx, eax
//pop eax
IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
IA32_Push_Reg(jit, REG_EAX);
IA32_Mov_Reg_Imm32(jit, REG_EAX, jit_int32_t(&co->plugin->codebase));
IA32_Mov_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_MEM_REG);
IA32_Add_Reg_Rm(jit, REG_ECX, REG_EAX, MOD_REG);
IA32_Pop_Reg(jit, REG_EAX);
/* Set up run-time registers */
//mov edi, [edx+SP] ;non-reloc SP
//add edi, eax ;reloc SP
//mov ebp, eax ;DAT
//mov ebx, edi ;reloc FRM
//mov [esi+NSTACK], esp ;save ESP
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EDX, offsetof(sp_context_t, sp));
IA32_Add_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_REG);
IA32_Mov_Reg_Rm(jit, REG_EBP, REG_EAX, MOD_REG);
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_EDI, MOD_REG);
IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ESP, AMX_INFO_NSTACK);
/* 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 ecx, [esi+8] - get retval pointer
//mov [ecx], eax - store retval from PRI
//mov eax, SP_ERROR_NONE - set no error
//mov ecx, [esi+RETVAL] ;get retval pointer
//mov [ecx], eax ;store retval from PRI
//mov eax, SP_ERROR_NONE ;set no error
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_ERROR_NONE);
/* save where error checking/halting functions should go to */
jitoffs_t offs_return = jit->get_outputpos();
//mov esp, esi - restore stack pointer
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
//mov esp, [esi+NSTACK] ;restore stack pointer
IA32_Mov_Reg_Rm_Disp8(jit, REG_ESP, REG_ESI, AMX_INFO_NSTACK);
/* _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]
/* Restore SP */
//mov ecx, [esi+CONTEXT]
//sub edi, ebp
//mov edx, [esi+heap]
//mov [ecx+sp], edi
//mov [ecx+hp], edx
//mov [ecx+SP], edi
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_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
//add esp, 4*NUM_INFO_PARAMS
//pop ebx
//pop edi
//pop esi
//pop ebp
//ret
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);
@@ -165,58 +123,22 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
return offs_return;
}
void Write_BreakDebug(JitWriter *jit)
{
//push edi
//mov edi, ecx
//mov ecx, [esi+ctx]
IA32_Push_Reg(jit, REG_EDI);
IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
//:TODO: align the stack to 16bytes like in sysreq.x
/* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
//pushad
//push [esi+frm]
//push [ctx+basectx]
//mov ecx, <dbreak>
//call ecx
//add esp, 8
//popad
IA32_Pushad(jit);
IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, vm[JITVARS_BASECTX]));
IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit_int32_t(((CompData *)jit->data)->plugin->dbreak));
IA32_Call_Reg(jit, AMX_REG_TMP);
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
IA32_Popad(jit);
//pop edi
//ret
IA32_Pop_Reg(jit, REG_EDI);
IA32_Return(jit);
}
void Write_GetError(JitWriter *jit)
{
CompData *data = (CompData *)jit->data;
//mov eax, [esi+info.context]
//mov eax, [eax+ctx.error]
//jmp [jit_return]
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
IA32_Jump_Imm32_Abs(jit, data->jit_return);
IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
}
void Write_SetError(JitWriter *jit, int error)
{
CompData *data = (CompData *)jit->data;
//mov eax, <error>
//jmp [jit_return]
IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
IA32_Jump_Imm32_Abs(jit, data->jit_return);
IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
}
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
@@ -224,7 +146,7 @@ void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
//test reg, reg
//jz :error
IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
IA32_Jump_Cond_Imm32_Rel(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
}
void Write_CheckHeap_Min(JitWriter *jit)
@@ -238,7 +160,7 @@ void Write_CheckHeap_Min(JitWriter *jit)
//cmp [esi+info.heap], <heaplow>
//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);
IA32_Jump_Cond_Imm32_Rel(jit, CC_B, data->jit_error_heapmin);
}
void Write_CheckHeap_Low(JitWriter *jit)
@@ -252,7 +174,7 @@ void Write_CheckHeap_Low(JitWriter *jit)
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);
IA32_Jump_Cond_Imm32_Rel(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
}
void Write_CheckStack_Min(JitWriter *jit)
@@ -263,7 +185,7 @@ void Write_CheckStack_Min(JitWriter *jit)
//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);
IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
}
void Write_CheckStack_Low(JitWriter *jit)
@@ -279,36 +201,15 @@ void Write_CheckStack_Low(JitWriter *jit)
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);
IA32_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
}
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
{
CompData *data = (CompData *)jit->data;
/* :TODO: Should this be checking for below heaplow?
* The old JIT did not.
*/
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 ((reg == REG_EAX) && data->jit_verify_addr_eax)
{
jitoffs_t call = IA32_Call_Imm32(jit, 0);
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;
}
/**
* :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!
@@ -318,7 +219,7 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
//cmp <reg>, <stpu>
//jae :error
IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->mem_size);
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
IA32_Jump_Cond_Imm32_Rel(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;
@@ -332,13 +233,8 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
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_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
IA32_Send_Jump8_Here(jit, jmp);
if (call)
{
IA32_Return(jit);
}
}
void Macro_PushN_Addr(JitWriter *jit, int i)
@@ -472,12 +368,7 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit)
//call NativeCallback
IA32_Push_Reg(jit, REG_EAX);
jitoffs_t call = IA32_Call_Imm32(jit, 0);
if (!data->debug)
{
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
} else {
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
}
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
/* Test for error */
//mov ecx, [esi+context]
@@ -485,7 +376,7 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit)
//jnz :error
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, data->jit_extern_error);
/* restore what we damaged */
//mov esp, ebx
@@ -594,6 +485,8 @@ void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _d
*/
void WriteIntrinsic_GenArray(JitWriter *jit)
{
jitoffs_t err1, err2;
/**
* save important values
*/
@@ -635,18 +528,18 @@ void WriteIntrinsic_GenArray(JitWriter *jit)
/* Test if we have heap space for this */
//mov eax, [esi+info.heap] ;get heap pointer
//lea eax, [eax+edx*4] ;new heap pointer
//cmp eax, <hlw> ;compare to heap low
//cmp eax, [esi+info.datasz] ;compare to heap low
//jbe :error ;die if we hit this (it should always be >)
//add eax, ebp ;relocate to stack
//cmp eax, edi ;die if above the stack pointer
//jae :error
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
IA32_Cmp_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_DATASIZE);
err1 = IA32_Jump_Cond_Imm32(jit, CC_BE, 0);
IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
err2 = IA32_Jump_Cond_Imm32(jit, CC_AE, 0);
/* Prepare for indirection iteration */
//mov eax, [esi+info.heap] ;get heap pointer
@@ -697,107 +590,15 @@ void WriteIntrinsic_GenArray(JitWriter *jit)
IA32_Pop_Reg(jit, REG_EAX);
IA32_Pop_Reg(jit, REG_EBX);
IA32_Return(jit);
}
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);
/* Align the stack to 16 bytes */
//push ebx
//mov ebx, esp
//and esp, 0xFFFFFF0
//sub esp, 4
IA32_Push_Reg(jit, REG_EBX);
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
/* 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 */
//mov eax, [esi+context]
//mov ecx, [esi+hea]
//sub edi, ebp
//mov [eax+hp], ecx
//mov ecx, [esi]
//mov [eax+sp], edi
//mov [eax+frm], ecx
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
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
//call NativeCallback
IA32_Push_Reg(jit, REG_EAX);
jitoffs_t call = IA32_Call_Imm32(jit, 0);
if (!data->debug)
{
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
} else {
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
}
/* Test for error */
//mov ecx, [esi+context]
//cmp [ecx+err], 0
//jnz :error
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
/* restore what we damaged */
//mov esp, ebx
//pop ebx
//add edi, ebp
//pop edx
//pop ecx ; num_params
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
IA32_Pop_Reg(jit, REG_EBX);
IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Pop_Reg(jit, AMX_REG_ALT);
IA32_Pop_Reg(jit, REG_ECX);
/* 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);
//:error
IA32_Send_Jump32_Here(jit, err1);
IA32_Send_Jump32_Here(jit, err2);
Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG);
}
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
{
CompData *data = (CompData *)jit->data;
/* Save registers that may be damaged by the call */
//push eax
//push ecx
@@ -824,7 +625,7 @@ void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
//cmp eax, 0
//jnz :error
IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
/* Restore */
//pop eax
@@ -890,13 +691,6 @@ int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
return SP_ERROR_NONE;
}
void Write_RoundingTable(JitWriter *jit)
{
jit->write_int32(-1);
jit->write_int32(0);
jit->write_int32(1);
}
void AlignMe(JitWriter *jit)
{
jitoffs_t cur_offs = jit->get_outputpos();
+3 -7
View File
@@ -44,7 +44,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit);
/**
* Writes the Sysreq.* opcodes as a function call.
*/
void WriteOp_Sysreq_N_Function(JitWriter *jit);
void WriteOp_Sysreq_C_Function(JitWriter *jit);
/**
@@ -52,6 +51,8 @@ void WriteOp_Sysreq_C_Function(JitWriter *jit);
*/
void WriteIntrinsic_GenArray(JitWriter *jit);
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg);
/**
* Generates code to set an error state in the VM and return.
* This is used for generating the error set points in the VM.
@@ -73,12 +74,6 @@ void Write_CheckStack_Low(JitWriter *jit);
void Write_CheckHeap_Min(JitWriter *jit);
void Write_CheckHeap_Low(JitWriter *jit);
/**
* Verifies an address by register. The address must reside
* between DAT and HP and SP and STP.
*/
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg);
/**
* Checks for division by zero.
*/
@@ -303,6 +298,7 @@ typedef enum
OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays)
OP_STRADJUST_PRI, //VERIFIED
OP_STACKADJUST, //:TODO: VERIFY
OP_ENDPROC, //VERIFIED
OP_FABS, //VERIFIED
OP_FLOAT, //VERIFIED
OP_FLOATADD, //VERIFIED
+6 -6
View File
@@ -676,12 +676,7 @@
}
case OP_SYSREQ_N:
{
if (data->inline_level & JIT_INLINE_NATIVES)
{
WriteOp_Sysreq_N(jit);
} else {
WriteOp_Sysreq_N_NoInline(jit);
}
WriteOp_Sysreq_N(jit);
break;
}
case OP_TRACKER_PUSH_C:
@@ -769,6 +764,11 @@
WriteOp_StackAdjust(jit);
break;
}
case OP_ENDPROC:
{
WriteOp_EndProc(jit);
break;
}
#if defined USE_UNGEN_OPCODES
#include "ungen_opcode_switch.inc"
#endif