some reorganization
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40162
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
|
||||
#if defined HAVE_STDINT_H && !defined WIN32
|
||||
#include <stdint.h>
|
||||
typedef int8_t jit_int8_t;
|
||||
typedef uint8_t jit_uint8_t;
|
||||
typedef int32_t jit_int32_t;
|
||||
typedef uint32_t jit_uint32_t;
|
||||
typedef int64_t jit_int64_t;
|
||||
typedef uint64_t jit_uint64_t;
|
||||
#elif defined WIN32
|
||||
typedef __int8 jit_int8_t;
|
||||
typedef unsigned __int8 jit_uint8_t;
|
||||
typedef __int32 jit_int32_t;
|
||||
typedef unsigned __int32 jit_uint32_t;
|
||||
typedef __int64 jit_int64_t;
|
||||
typedef unsigned __int64 jit_uint64_t;
|
||||
#endif
|
||||
|
||||
typedef char * jitcode_t;
|
||||
typedef unsigned int jitoffs_t;
|
||||
typedef signed int jitrel_t;
|
||||
|
||||
class JitWriter
|
||||
{
|
||||
public:
|
||||
inline cell_t read_cell()
|
||||
{
|
||||
cell_t val = *(inptr);
|
||||
inptr++;
|
||||
return val;
|
||||
}
|
||||
inline cell_t *read_cellptr()
|
||||
{
|
||||
cell_t *val = *(cell_t **)(inptr);
|
||||
inptr++;
|
||||
return val;
|
||||
}
|
||||
inline void write_ubyte(jit_uint8_t c)
|
||||
{
|
||||
if (outbase)
|
||||
{
|
||||
*outptr = c;
|
||||
}
|
||||
outptr++;
|
||||
}
|
||||
inline void write_byte(jit_int8_t c)
|
||||
{
|
||||
if (outbase)
|
||||
{
|
||||
*outptr = c;
|
||||
}
|
||||
outptr++;
|
||||
}
|
||||
inline void write_int32(jit_int32_t c)
|
||||
{
|
||||
if (outbase)
|
||||
{
|
||||
*(jit_int32_t *)outptr = c;
|
||||
}
|
||||
outptr += sizeof(jit_int32_t);
|
||||
}
|
||||
inline void write_uint32(jit_uint32_t c)
|
||||
{
|
||||
if (outbase)
|
||||
{
|
||||
*(jit_uint32_t *)outptr = c;
|
||||
}
|
||||
outptr += sizeof(jit_uint32_t);
|
||||
}
|
||||
inline jitoffs_t get_outputpos()
|
||||
{
|
||||
return (outptr - outbase);
|
||||
}
|
||||
inline void set_outputpos(jitoffs_t offs)
|
||||
{
|
||||
outptr = outbase + offs;
|
||||
}
|
||||
inline jitoffs_t get_inputpos()
|
||||
{
|
||||
return (jitoffs_t)((char *)inptr - (char *)inbase);
|
||||
}
|
||||
public:
|
||||
cell_t *inptr; /* input pointer */
|
||||
cell_t *inbase; /* input base */
|
||||
jitcode_t outbase; /* output pointer */
|
||||
jitcode_t outptr; /* output base */
|
||||
SourcePawn::ICompilation *data; /* compiler live info */
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_HELPERS_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <sp_vm_api.h>
|
||||
#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 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_
|
||||
|
||||
#include <sp_vm_base.h>
|
||||
|
||||
#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_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include "..\jit_helpers.h"
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define JIT_INLINE_ERRORCHECKS (1<<0)
|
||||
#define JIT_INLINE_NATIVES (1<<1)
|
||||
#define STACK_MARGIN 64 //8 parameters of safety, I guess
|
||||
|
||||
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
|
||||
|
||||
typedef struct tracker_s
|
||||
{
|
||||
size_t size;
|
||||
ucell_t *pBase;
|
||||
ucell_t *pCur;
|
||||
} tracker_t;
|
||||
|
||||
class CompData : public ICompilation
|
||||
{
|
||||
public:
|
||||
CompData() : plugin(NULL),
|
||||
debug(false), inline_level(0), rebase(NULL),
|
||||
error_set(SP_ERROR_NONE)
|
||||
{
|
||||
};
|
||||
public:
|
||||
sp_plugin_t *plugin; /* plugin handle */
|
||||
jitcode_t rebase; /* relocation map */
|
||||
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;
|
||||
jitoffs_t jit_error_stackmin;
|
||||
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_error_tracker_bounds;
|
||||
jitoffs_t jit_extern_error; /* returning generic error */
|
||||
jitoffs_t jit_sysreq_c; /* old version! */
|
||||
uint32_t codesize; /* total codesize */
|
||||
int inline_level; /* inline optimization level */
|
||||
int error_set; /* error code to halt process */
|
||||
bool debug; /* whether to compile debug mode */
|
||||
};
|
||||
|
||||
class JITX86 : public IVirtualMachine
|
||||
{
|
||||
public:
|
||||
const char *GetVMName();
|
||||
ICompilation *StartCompilation(sp_plugin_t *plugin);
|
||||
bool SetCompilationOption(ICompilation *co, const char *key, const char *val);
|
||||
sp_context_t *CompileToContext(ICompilation *co, int *err);
|
||||
void AbortCompilation(ICompilation *co);
|
||||
void FreeContext(sp_context_t *ctx);
|
||||
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);
|
||||
cell_t NativeCallback_Debug(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
|
||||
#define AMX_REG_ALT REG_EDX
|
||||
#define AMX_REG_STK REG_EDI
|
||||
#define AMX_REG_DAT REG_EBP
|
||||
#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 //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
|
||||
|
||||
extern ISourcePawnEngine *engine;
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
@@ -0,0 +1,779 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "jit_x86.h"
|
||||
#include "opcode_helpers.h"
|
||||
#include "x86_macros.h"
|
||||
|
||||
#define NUM_INFO_PARAMS 5
|
||||
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit)
|
||||
{
|
||||
/**
|
||||
* 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*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);
|
||||
|
||||
/* 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, [eax+<offs>] - 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_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, 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_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
|
||||
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)
|
||||
//add ecx, [eax+<offs>] - 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));
|
||||
|
||||
/* 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
|
||||
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);
|
||||
|
||||
/* _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_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);
|
||||
IA32_Pop_Reg(jit, REG_EBP);
|
||||
IA32_Return(jit);
|
||||
|
||||
return offs_return;
|
||||
}
|
||||
|
||||
void Write_BreakDebug(JitWriter *jit)
|
||||
{
|
||||
//push ecx
|
||||
//mov ecx, [esi+ctx]
|
||||
//cmp [ecx+dbreak], 0
|
||||
//jnz :nocall
|
||||
IA32_Push_Reg(jit, AMX_REG_TMP);
|
||||
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, dbreak), 0);
|
||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
|
||||
|
||||
//pushad
|
||||
IA32_Pushad(jit);
|
||||
|
||||
//push [esi+frm]
|
||||
//push [ecx+context]
|
||||
//mov ecx, [ecx+dbreak]
|
||||
//call ecx
|
||||
//add esp, 8
|
||||
//popad
|
||||
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, context));
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
|
||||
IA32_Call_Reg(jit, AMX_REG_TMP);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
|
||||
IA32_Popad(jit);
|
||||
|
||||
//:nocall
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG);
|
||||
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, err));
|
||||
IA32_Jump_Imm32_Abs(jit, data->jit_return);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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], <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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* :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!
|
||||
*/
|
||||
|
||||
/* Part 1: Check if we're in the memory bounds */
|
||||
//cmp <reg>, <stpu>
|
||||
//jae :error
|
||||
IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
|
||||
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 <reg>, [esi+info.heap]
|
||||
//jb :continue
|
||||
//lea ecx, [ebp+<reg>]
|
||||
//cmp edi, ecx
|
||||
//jb :error
|
||||
//:continue
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
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 Macro_PushN_Addr(JitWriter *jit, int i)
|
||||
{
|
||||
//push eax
|
||||
//mov eax, [esi+frm]
|
||||
//loop i times:
|
||||
// lea ecx, [eax+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
//pop eax
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
|
||||
else
|
||||
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);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
void Macro_PushN_S(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebx+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
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
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN_C(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov [edi-4*i], <val>
|
||||
//sub edi, 4*N
|
||||
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebp+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
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
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void WriteOp_Sysreq_C_Function(JitWriter *jit)
|
||||
{
|
||||
/* The small daddy of the big daddy of opcodes.
|
||||
* ecx - native index
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* save registers we will need */
|
||||
//push edx
|
||||
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 */
|
||||
//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, NativeCallback);
|
||||
} else {
|
||||
IA32_Write_Jump32_Abs(jit, call, 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, err), 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
|
||||
|
||||
/* 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_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
//ret
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero)
|
||||
{
|
||||
cell_t vectors = 1; /* we need one vector to start off with */
|
||||
cell_t cur_offs = 0;
|
||||
cell_t cur_write = 0;
|
||||
cell_t dimcount = _dimcount;
|
||||
|
||||
/* Initialize rotation */
|
||||
cur_write = dims[dimcount-1];
|
||||
|
||||
while (--dimcount >= 1)
|
||||
{
|
||||
cell_t cur_dim = dims[dimcount];
|
||||
cell_t sub_dim = dims[dimcount-1];
|
||||
for (cell_t i=0; i<vectors; i++)
|
||||
{
|
||||
for (cell_t j=0; j<cur_dim; j++)
|
||||
{
|
||||
arraybase[cur_offs] = (cur_write - cur_offs)*sizeof(cell_t);
|
||||
cur_offs++;
|
||||
cur_write += sub_dim;
|
||||
}
|
||||
}
|
||||
vectors = cur_dim;
|
||||
}
|
||||
|
||||
/* everything after cur_offs can be zeroed */
|
||||
if (autozero)
|
||||
{
|
||||
size_t size = 1;
|
||||
for (ucell_t i=0; i<_dimcount; i++)
|
||||
{
|
||||
size *= dims[i];
|
||||
}
|
||||
memset(&arraybase[cur_offs], 0, size*sizeof(cell_t));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* A few notes about this function.
|
||||
* I was more concerned about efficient use of registers here, rather than
|
||||
* fine-tuned optimization. The reason is that the code is already complicated,
|
||||
* and it is very easy to mess up.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit)
|
||||
{
|
||||
/**
|
||||
* save important values
|
||||
*/
|
||||
//push ebx
|
||||
//push eax
|
||||
//push edx
|
||||
//push ecx ;value is referenced on stack
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
IA32_Push_Reg(jit, REG_EDX);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/**
|
||||
* Calculate how many cells will be needed.
|
||||
*/
|
||||
//mov edx, [edi] ;get last dimension's count
|
||||
//mov eax, 1 ;position at second to last dimension
|
||||
//:loop
|
||||
//cmp eax, [esp] ;compare to # of params
|
||||
//jae :done ;end loop if done
|
||||
//mov ecx, [edi+eax*4] ;get dimension size
|
||||
//imul edx, ecx ;multiply by size
|
||||
//add eax, 1 ;increment
|
||||
//add edx, ecx ;add size (indirection vector)
|
||||
//jmp :loop ;jump back
|
||||
//:done
|
||||
IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
|
||||
jitoffs_t loop1 = jit->get_outputpos();
|
||||
IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
|
||||
jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
|
||||
IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
|
||||
IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
|
||||
IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
|
||||
IA32_Send_Jump8_Here(jit, done1);
|
||||
|
||||
/* 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
|
||||
//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_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);
|
||||
|
||||
/* Prepare for indirection iteration */
|
||||
//mov eax, [esi+info.heap] ;get heap pointer
|
||||
//lea ebx, [eax+edx*4] ;new heap pointer
|
||||
//mov [esi+info.heap], ebx ;store back
|
||||
//push eax ;save heap pointer - we need it
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
|
||||
WriteOp_Tracker_Push_Reg(jit, REG_EDX);
|
||||
|
||||
/* This part is too messy to do in straight assembly.
|
||||
* I'm letting the compiler handle it and thus it's in C.
|
||||
*/
|
||||
//lea ebx, [ebp+eax] ;get base pointer
|
||||
//push dword [esp-8] ;push autozero
|
||||
//push dword [esp-8] ;push dimension count
|
||||
//push edi ;push dim array
|
||||
//push ebx
|
||||
//call GenerateArrayIndirectionVectors
|
||||
//add esp, 4*4
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
|
||||
|
||||
/* Store the heap pointer back into the stack */
|
||||
//pop eax ;restore heap pointer
|
||||
//pop ecx ;restore param count
|
||||
//lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
|
||||
//mov [edi], eax ;store back the heap pointer
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
|
||||
|
||||
/* Return to caller */
|
||||
//pop edx
|
||||
//pop eax
|
||||
//pop ebx
|
||||
//ret
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
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);
|
||||
|
||||
/* 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, NativeCallback);
|
||||
} else {
|
||||
IA32_Write_Jump32_Abs(jit, call, 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, err), 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
|
||||
|
||||
/* 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_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);
|
||||
}
|
||||
|
||||
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
|
||||
//push edi
|
||||
//lea edi, [<reg>*4] ; we want the count in bytes not in cells
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Push_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
|
||||
|
||||
/* Get the context ptr, push it and call the check */
|
||||
//mov eax, [esi+context]
|
||||
//push eax
|
||||
//call JIT_VerifyOrAllocateTracker
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
|
||||
|
||||
/* Check for errors */
|
||||
//pop eax
|
||||
//cmp [eax+err], 0
|
||||
//jnz :error
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
|
||||
|
||||
/* Push the register into the stack and increment pCur */
|
||||
//mov edx, [eax+vm[]]
|
||||
//mov eax, [edx+pcur]
|
||||
//add [edx+pcur], 4
|
||||
//mov [eax], edi
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
|
||||
IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
|
||||
IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
|
||||
|
||||
/* Restore PRI, ALT and STK */
|
||||
//pop edi
|
||||
//pop ecx
|
||||
//pop eax
|
||||
IA32_Pop_Reg(jit, AMX_REG_STK);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Pop_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
void JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
|
||||
|
||||
if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
|
||||
{
|
||||
ctx->err = SP_ERROR_TRACKER_BOUNDS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
|
||||
{
|
||||
size_t disp = trk->size - 1;
|
||||
trk->size *= 2;
|
||||
trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
|
||||
|
||||
if (!trk->pBase)
|
||||
{
|
||||
ctx->err = SP_ERROR_TRACKER_BOUNDS;
|
||||
return;
|
||||
}
|
||||
|
||||
trk->pCur = trk->pBase + disp;
|
||||
}
|
||||
}
|
||||
|
||||
void JIT_VerifyLowBoundTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
|
||||
|
||||
if (trk->pCur <= trk->pBase)
|
||||
{
|
||||
ctx->err = SP_ERROR_TRACKER_BOUNDS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
|
||||
#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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* Write the GENARRAY intrinsic function.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Generates code to set an error state in the VM and return.
|
||||
* This is used for generating the error set points in the VM.
|
||||
* GetError writes the error from the context. SetError hardcodes.
|
||||
*/
|
||||
void Write_GetError(JitWriter *jit);
|
||||
void Write_SetError(JitWriter *jit, int error);
|
||||
|
||||
/**
|
||||
* Checks the stacks for min and low errors.
|
||||
* :TODO: Should a variation of this go in the pushN opcodes?
|
||||
*/
|
||||
void Write_CheckStack_Min(JitWriter *jit);
|
||||
void Write_CheckStack_Low(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Checks the heap for min and low errors.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg);
|
||||
|
||||
/**
|
||||
* Writes the break debug function.
|
||||
*/
|
||||
void Write_BreakDebug(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
void Macro_PushN(JitWriter *jit, int i);
|
||||
|
||||
/**
|
||||
* Bound checking for the tracker stack,
|
||||
*/
|
||||
void JIT_VerifyLowBoundTracker(sp_context_t *ctx);
|
||||
void JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Writes the push into tracker function.
|
||||
*/
|
||||
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg);
|
||||
|
||||
/**
|
||||
* 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, //!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, //VERIFIED
|
||||
OP_LREF_S_ALT, //~VERIFIED (lref.s.pri)
|
||||
OP_LOAD_I, //VERIFIED
|
||||
OP_LODB_I, //VERIFIED
|
||||
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, //VERIFIED
|
||||
OP_LIDX, //VERIFIED
|
||||
OP_LIDX_B, //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, //~VERIFIED (move.alt)
|
||||
OP_MOVE_ALT, //VERIFIED
|
||||
OP_XCHG, //DONE
|
||||
OP_PUSH_PRI, //DONE
|
||||
OP_PUSH_ALT, //DONE
|
||||
OP_PUSH_R, // !GEN DEPRECATED
|
||||
OP_PUSH_C, //VERIFIED
|
||||
OP_PUSH, //DONE
|
||||
OP_PUSH_S, //VERIFIED
|
||||
OP_POP_PRI, //VERIFIED
|
||||
OP_POP_ALT, //VERIFIED
|
||||
OP_STACK, //VERIFIED
|
||||
OP_HEAP, //VERIFIED
|
||||
OP_PROC, //VERIFIED
|
||||
OP_RET, // !GEN
|
||||
OP_RETN, //VERIFIED
|
||||
OP_CALL, //VERIFIED
|
||||
OP_CALL_PRI, // !GEN
|
||||
OP_JUMP, //VERIFIED
|
||||
OP_JREL, // !GEN
|
||||
OP_JZER, //VERIFIED
|
||||
OP_JNZ, //DONE
|
||||
OP_JEQ, //VERIFIED
|
||||
OP_JNEQ, //VERIFIED
|
||||
OP_JLESS, // !GEN
|
||||
OP_JLEQ, // !GEN
|
||||
OP_JGRTR, // !GEN
|
||||
OP_JGEQ, // !GEN
|
||||
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, //VERIFIED
|
||||
OP_SDIV, //DONE
|
||||
OP_SDIV_ALT, //VERIFIED
|
||||
OP_UMUL, // !GEN
|
||||
OP_UDIV, // !GEN
|
||||
OP_UDIV_ALT, // !GEN
|
||||
OP_ADD, //VERIFIED
|
||||
OP_SUB, //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, //VERIFIED
|
||||
OP_NEQ, //VERIFIED
|
||||
OP_LESS, // !GEN
|
||||
OP_LEQ, // !GEN
|
||||
OP_GRTR, // !GEN
|
||||
OP_GEQ, // !GEN
|
||||
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, //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, //VERIFIED
|
||||
OP_CMPS, // !GEN
|
||||
OP_FILL, //VERIFIED
|
||||
OP_HALT, //DONE
|
||||
OP_BOUNDS, //VERIFIED
|
||||
OP_SYSREQ_PRI, // !GEN
|
||||
OP_SYSREQ_C, //VERIFIED
|
||||
OP_FILE, // !GEN DEPRECATED
|
||||
OP_LINE, // !GEN DEPRECATED
|
||||
OP_SYMBOL, // !GEN DEPRECATED
|
||||
OP_SRANGE, // !GEN DEPRECATED
|
||||
OP_JUMP_PRI, // !GEN
|
||||
OP_SWITCH, //VERIFIED
|
||||
OP_CASETBL, //VERIFIED
|
||||
OP_SWAP_PRI, //VERIFIED
|
||||
OP_SWAP_ALT, //~VERIFIED (swap.alt)
|
||||
OP_PUSH_ADR, //VERIFIED
|
||||
OP_NOP, //VERIFIED (lol)
|
||||
OP_SYSREQ_N, //VERIFIED
|
||||
OP_SYMTAG, // !GEN DEPRECATED
|
||||
OP_BREAK, //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
|
||||
OP_SYSREQ_ND, // !GEN UNSUPPORT
|
||||
/* ----- */
|
||||
OP_TRACKER_PUSH_C, //DONE
|
||||
OP_TRACKER_POP_SETHEAP, //VERIFIED
|
||||
OP_GENARRAY, //VERIFIED
|
||||
OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays)
|
||||
/* ----- */
|
||||
OP_NUM_OPCODES
|
||||
} OPCODE;
|
||||
|
||||
/*
|
||||
* :TODO: List of ASM Opts
|
||||
* from jit_x86.cpp
|
||||
* DONE: Rest of opcodes including the SYSREQ.N inlined version (rev2)
|
||||
* Including genarray and the 2 tracker ones
|
||||
* DONE: ALL ungen opcodes (rev1)
|
||||
* from opcode_helpers.cpp
|
||||
* DONE: SYSREQ.N .C (rev2)
|
||||
* MACRO OPCODES (rev2)
|
||||
* ERROR CHECKS\{VERIFY ADDR} (rev2)
|
||||
* ARRAY STUFF
|
||||
* TODO: BrkDebug
|
||||
* EXEC FUNCTION
|
||||
* VERIFY ADDR
|
||||
*
|
||||
* Oh and ALIGN all stuff that is called via CALL like what's done with PROC.
|
||||
*/
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
@@ -0,0 +1,684 @@
|
||||
case OP_MOVE_PRI:
|
||||
{
|
||||
WriteOp_Move_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVE_ALT:
|
||||
{
|
||||
WriteOp_Move_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XCHG:
|
||||
{
|
||||
WriteOp_Xchg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH:
|
||||
{
|
||||
WriteOp_Push(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_S:
|
||||
{
|
||||
WriteOp_Push_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_C:
|
||||
{
|
||||
WriteOp_Push2_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_C:
|
||||
{
|
||||
WriteOp_Push3_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_C:
|
||||
{
|
||||
WriteOp_Push4_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_C:
|
||||
{
|
||||
WriteOp_Push5_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_ADR:
|
||||
{
|
||||
WriteOp_Push2_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_ADR:
|
||||
{
|
||||
WriteOp_Push3_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_ADR:
|
||||
{
|
||||
WriteOp_Push4_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_ADR:
|
||||
{
|
||||
WriteOp_Push5_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_S:
|
||||
{
|
||||
WriteOp_Push2_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_S:
|
||||
{
|
||||
WriteOp_Push3_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_S:
|
||||
{
|
||||
WriteOp_Push4_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_S:
|
||||
{
|
||||
WriteOp_Push5_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5:
|
||||
{
|
||||
WriteOp_Push5(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4:
|
||||
{
|
||||
WriteOp_Push4(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3:
|
||||
{
|
||||
WriteOp_Push3(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2:
|
||||
{
|
||||
WriteOp_Push2(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_PRI:
|
||||
{
|
||||
WriteOp_Zero_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_ALT:
|
||||
{
|
||||
WriteOp_Zero_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PROC:
|
||||
{
|
||||
WriteOp_Proc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL:
|
||||
{
|
||||
WriteOp_Shl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR:
|
||||
{
|
||||
WriteOp_Shr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SSHR:
|
||||
{
|
||||
WriteOp_Sshr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_PRI:
|
||||
{
|
||||
WriteOp_Shl_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_ALT:
|
||||
{
|
||||
WriteOp_Shl_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_PRI:
|
||||
{
|
||||
WriteOp_Shr_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_ALT:
|
||||
{
|
||||
WriteOp_Shr_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL:
|
||||
{
|
||||
WriteOp_SMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD:
|
||||
{
|
||||
WriteOp_Add(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB:
|
||||
{
|
||||
WriteOp_Sub(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB_ALT:
|
||||
{
|
||||
WriteOp_Sub_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NOP:
|
||||
{
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
case OP_NOT:
|
||||
{
|
||||
WriteOp_Not(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEG:
|
||||
{
|
||||
WriteOp_Neg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XOR:
|
||||
{
|
||||
WriteOp_Xor(jit);
|
||||
break;
|
||||
}
|
||||
case OP_OR:
|
||||
{
|
||||
WriteOp_Or(jit);
|
||||
break;
|
||||
}
|
||||
case OP_AND:
|
||||
{
|
||||
WriteOp_And(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INVERT:
|
||||
{
|
||||
WriteOp_Invert(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD_C:
|
||||
{
|
||||
WriteOp_Add_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL_C:
|
||||
{
|
||||
WriteOp_SMul_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_PRI:
|
||||
{
|
||||
WriteOp_Sign_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_ALT:
|
||||
{
|
||||
WriteOp_Sign_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ:
|
||||
{
|
||||
WriteOp_Eq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEQ:
|
||||
{
|
||||
WriteOp_Neq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLESS:
|
||||
{
|
||||
WriteOp_Sless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLEQ:
|
||||
{
|
||||
WriteOp_Sleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGRTR:
|
||||
{
|
||||
WriteOp_Sgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGEQ:
|
||||
{
|
||||
WriteOp_Sgeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_PRI:
|
||||
{
|
||||
WriteOp_Eq_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_ALT:
|
||||
{
|
||||
WriteOp_Eq_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_PRI:
|
||||
{
|
||||
WriteOp_Inc_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_ALT:
|
||||
{
|
||||
WriteOp_Inc_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC:
|
||||
{
|
||||
WriteOp_Inc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_S:
|
||||
{
|
||||
WriteOp_Inc_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_I:
|
||||
{
|
||||
WriteOp_Inc_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_PRI:
|
||||
{
|
||||
WriteOp_Dec_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_ALT:
|
||||
{
|
||||
WriteOp_Dec_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC:
|
||||
{
|
||||
WriteOp_Dec(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_S:
|
||||
{
|
||||
WriteOp_Dec_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_I:
|
||||
{
|
||||
WriteOp_Dec_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_PRI:
|
||||
{
|
||||
WriteOp_Load_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_ALT:
|
||||
{
|
||||
WriteOp_Load_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_PRI:
|
||||
{
|
||||
WriteOp_Load_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_ALT:
|
||||
{
|
||||
WriteOp_Load_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_PRI:
|
||||
{
|
||||
WriteOp_Lref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_ALT:
|
||||
{
|
||||
WriteOp_Lref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_PRI:
|
||||
{
|
||||
WriteOp_Lref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_ALT:
|
||||
{
|
||||
WriteOp_Lref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_PRI:
|
||||
{
|
||||
WriteOp_Const_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_ALT:
|
||||
{
|
||||
WriteOp_Const_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_PRI:
|
||||
{
|
||||
WriteOp_Addr_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_ALT:
|
||||
{
|
||||
WriteOp_Addr_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_PRI:
|
||||
{
|
||||
WriteOp_Stor_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_ALT:
|
||||
{
|
||||
WriteOp_Stor_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_PRI:
|
||||
{
|
||||
WriteOp_Stor_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_ALT:
|
||||
{
|
||||
WriteOp_Stor_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR:
|
||||
{
|
||||
WriteOp_Idxaddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_PRI:
|
||||
{
|
||||
WriteOp_Sref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_ALT:
|
||||
{
|
||||
WriteOp_Sref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_PRI:
|
||||
{
|
||||
WriteOp_Sref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_ALT:
|
||||
{
|
||||
WriteOp_Sref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_PRI:
|
||||
{
|
||||
WriteOp_Pop_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_ALT:
|
||||
{
|
||||
WriteOp_Pop_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_PRI:
|
||||
{
|
||||
WriteOp_Swap_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_ALT:
|
||||
{
|
||||
WriteOp_Swap_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ADR:
|
||||
{
|
||||
WriteOp_PushAddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVS:
|
||||
{
|
||||
WriteOp_Movs(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FILL:
|
||||
{
|
||||
WriteOp_Fill(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_C:
|
||||
{
|
||||
WriteOp_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO:
|
||||
{
|
||||
WriteOp_Zero(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_S:
|
||||
{
|
||||
WriteOp_Zero_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_PRI:
|
||||
{
|
||||
WriteOp_Push_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ALT:
|
||||
{
|
||||
WriteOp_Push_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_BOTH:
|
||||
{
|
||||
WriteOp_Load_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_BOTH:
|
||||
{
|
||||
WriteOp_Load_S_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST:
|
||||
{
|
||||
WriteOp_Const(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_S:
|
||||
{
|
||||
WriteOp_Const_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_I:
|
||||
{
|
||||
WriteOp_Load_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LODB_I:
|
||||
{
|
||||
WriteOp_Lodb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_I:
|
||||
{
|
||||
WriteOp_Stor_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STRB_I:
|
||||
{
|
||||
WriteOp_Strb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX:
|
||||
{
|
||||
WriteOp_Lidx(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX_B:
|
||||
{
|
||||
WriteOp_Lidx_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR_B:
|
||||
{
|
||||
WriteOp_Idxaddr_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STACK:
|
||||
{
|
||||
WriteOp_Stack(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HEAP:
|
||||
{
|
||||
WriteOp_Heap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV:
|
||||
{
|
||||
WriteOp_SDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV_ALT:
|
||||
{
|
||||
WriteOp_SDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RETN:
|
||||
{
|
||||
WriteOp_Retn(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BOUNDS:
|
||||
{
|
||||
WriteOp_Bounds(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HALT:
|
||||
{
|
||||
WriteOp_Halt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BREAK:
|
||||
{
|
||||
WriteOp_Break(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JUMP:
|
||||
{
|
||||
WriteOp_Jump(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JZER:
|
||||
{
|
||||
WriteOp_Jzer(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNZ:
|
||||
{
|
||||
WriteOp_Jnz(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNEQ:
|
||||
{
|
||||
WriteOp_Jneq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLESS:
|
||||
{
|
||||
WriteOp_Jsless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGRTR:
|
||||
{
|
||||
WriteOp_JsGrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGEQ:
|
||||
{
|
||||
WriteOp_JsGeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLEQ:
|
||||
{
|
||||
WriteOp_Jsleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWITCH:
|
||||
{
|
||||
WriteOp_Switch(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CASETBL:
|
||||
{
|
||||
WriteOp_Casetbl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
{
|
||||
WriteOp_Call(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_C:
|
||||
{
|
||||
WriteOp_Sysreq_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_N:
|
||||
{
|
||||
if (data->inline_level & JIT_INLINE_NATIVES)
|
||||
{
|
||||
WriteOp_Sysreq_N(jit);
|
||||
} else {
|
||||
WriteOp_Sysreq_N_NoInline(jit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_PUSH_C:
|
||||
{
|
||||
WriteOp_Tracker_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_POP_SETHEAP:
|
||||
{
|
||||
WriteOp_Tracker_Pop_SetHeap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY:
|
||||
{
|
||||
WriteOp_GenArray(jit, false);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY_Z:
|
||||
{
|
||||
WriteOp_GenArray(jit, true);
|
||||
break;
|
||||
}
|
||||
#if defined USE_UNGEN_OPCODES
|
||||
#include "ungen_opcode_switch.inc"
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
data->error_set = SP_ERROR_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
case OP_UMUL:
|
||||
{
|
||||
WriteOp_UMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LESS:
|
||||
{
|
||||
WriteOp_Less(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LEQ:
|
||||
{
|
||||
WriteOp_Leq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GRTR:
|
||||
{
|
||||
WriteOp_Grtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GEQ:
|
||||
{
|
||||
WriteOp_Geq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_PRI:
|
||||
{
|
||||
WriteOp_Align_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_ALT:
|
||||
{
|
||||
WriteOp_Align_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LCTRL:
|
||||
{
|
||||
WriteOp_Lctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SCTRL:
|
||||
{
|
||||
WriteOp_Sctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV:
|
||||
{
|
||||
WriteOp_UDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV_ALT:
|
||||
{
|
||||
WriteOp_UDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RET:
|
||||
{
|
||||
WriteOp_Ret(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CMPS:
|
||||
{
|
||||
WriteOp_Cmps(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JREL:
|
||||
{
|
||||
WriteOp_JRel(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLESS:
|
||||
{
|
||||
WriteOp_Jless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGRTR:
|
||||
{
|
||||
WriteOp_Jgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGEQ:
|
||||
{
|
||||
WriteOp_Jgeq(jit);
|
||||
break;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
|
||||
inline void WriteOp_UMul(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//mul edx
|
||||
//mov edx, ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Less(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI < ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setb al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B);
|
||||
}
|
||||
|
||||
inline void WriteOp_Leq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI <= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setbe al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Grtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI > ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//seta al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A);
|
||||
}
|
||||
|
||||
inline void WriteOp_Geq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI >= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setae al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Pri(JitWriter *jit)
|
||||
{
|
||||
//xor eax, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Eax_Imm32(jit, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Alt(JitWriter *jit)
|
||||
{
|
||||
//xor edx, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Cmps(JitWriter *jit)
|
||||
{
|
||||
//push edi
|
||||
//push esi
|
||||
//lea esi, [ebp+edx]
|
||||
//lea edi, [ebp+eax]
|
||||
//mov ecx, <val>
|
||||
unsigned int val = jit->read_cell();
|
||||
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_ESI);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
|
||||
|
||||
//xor eax, eax
|
||||
//repe cmpsb
|
||||
//je :cmps1
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Rep(jit);
|
||||
IA32_Cmpsb(jit);
|
||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0);
|
||||
|
||||
//sbb eax, eax
|
||||
//sbb eax, -1
|
||||
IA32_Sbb_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Sbb_Rm_Imm8(jit, AMX_REG_PRI, -1, MOD_REG);
|
||||
|
||||
//:cmps1
|
||||
//pop esi
|
||||
//pop edi
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
}
|
||||
|
||||
inline void WriteOp_Lctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.codebase]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, codebase));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
//mov eax, ebp
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
//mov eax, [esi+hea]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.memory]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory));
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//mov eax, edi
|
||||
//sub eax, ebp - unrelocate
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//mov eax, [esi+frm]
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
//mov eax, [cip]
|
||||
jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
jitoffs_t save = jit->get_outputpos();
|
||||
jit->set_outputpos(imm32);
|
||||
jit->write_int32((uint32_t)(jit->outbase + save));
|
||||
jit->set_outputpos(save);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Sctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
//mov [esi+hea], eax
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//lea edi, [ebp+eax]
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//lea ebx, [ebp+eax] - overwrite frm
|
||||
//mov [esi+frm], eax - overwrite stacked frame
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_FRM, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_PRI, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
IA32_Jump_Reg(jit, AMX_REG_PRI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv_Alt(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, eax
|
||||
//mov eax, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Ret(JitWriter *jit)
|
||||
{
|
||||
//mov ebx, [edi] - get old FRM
|
||||
//add edi, 4 - pop stack
|
||||
//mov [esi+frm], ebx - restore
|
||||
//add ebx, ebp - relocate
|
||||
//ret
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, 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);
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
inline void WriteOp_JRel(JitWriter *jit)
|
||||
{
|
||||
//jmp <offs> ;relative jump
|
||||
cell_t cip_offs = jit->read_cell();
|
||||
|
||||
/* Note that since code size calculation has to be done in the same
|
||||
* phase as building relocation information, we cannot know the jump size
|
||||
* beforehand. Thus, we always write full 32bit jumps for safety.
|
||||
*/
|
||||
jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jless(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jb <target>
|
||||
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_B, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jleq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jbe <target>
|
||||
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_BE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgrtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//ja <target>
|
||||
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_A, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgeq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jae <target>
|
||||
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_AE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user