Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann)

This commit is contained in:
David Anderson
2013-08-08 09:41:24 -07:00
parent ad543c909c
commit 9e56725406
26 changed files with 5150 additions and 7108 deletions
File diff suppressed because it is too large Load Diff
+136 -120
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 :
* vim: set ts=4 sw=4 tw=99 et:
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -35,164 +35,180 @@
#include <sp_vm_types.h>
#include <sp_vm_api.h>
#include <KeCodeAllocator.h>
#include "jit_helpers.h"
#include <assembler-x86.h>
#include <ke_vector.h>
#include "jit_shared.h"
#include "BaseRuntime.h"
#include "jit_function.h"
#include "opcodes.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 JIT_FUNCMAGIC 0x214D4148 //magic function offset
#define JIT_INLINE_ERRORCHECKS (1<<0)
#define JIT_INLINE_NATIVES (1<<1)
#define STACK_MARGIN 64 //8 parameters of safety, I guess
#define JIT_FUNCMAGIC 0x214D4148 //magic function offset
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
#define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM
#define JITVARS_PROFILER 2 //profiler
#define JITVARS_PLUGIN 3 //sp_plugin_t
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
#define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM
#define JITVARS_PROFILER 2 //profiler
#define JITVARS_PLUGIN 3 //sp_plugin_t
#define sDIMEN_MAX 5 //this must mirror what the compiler has.
#define sDIMEN_MAX 5 //this must mirror what the compiler has.
#define GET_CONTEXT(c) ((IPluginContext *)c->vm[JITVARS_BASECTX])
typedef struct tracker_s
{
size_t size;
ucell_t *pBase;
ucell_t *pCur;
size_t size;
ucell_t *pBase;
ucell_t *pCur;
} tracker_t;
typedef struct funcinfo_s
{
unsigned int magic;
unsigned int index;
unsigned int magic;
unsigned int index;
} funcinfo_t;
typedef struct functracker_s
{
unsigned int num_functions;
unsigned int code_size;
unsigned int num_functions;
unsigned int code_size;
} functracker_t;
struct floattbl_t
struct CallThunk
{
floattbl_t()
{
found = false;
index = 0;
}
bool found;
unsigned int index;
};
Label call;
cell_t pcode_offset;
struct call_thunk_t
{
jitoffs_t patch_addr;
cell_t pcode_offs;
jitoffs_t thunk_addr;
CallThunk(cell_t pcode_offset)
: pcode_offset(pcode_offset)
{
}
};
class CompData : public ICompilation
{
public:
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);
void SetRuntime(BaseRuntime *runtime);
void Abort();
CompData()
: profile(0),
inline_level(0)
{
};
bool SetOption(const char *key, const char *val);
void Abort();
public:
BaseRuntime *runtime; /* runtime handle */
sp_plugin_t *plugin; /* plugin handle */
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 */
/* Per-compilation properties */
int error_set; /* error code to halt process */
unsigned int func_idx; /* current function index */
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_extern_error; /* returning generic error */
jitoffs_t jit_sysreq_c; /* old version! */
uint32_t num_thunks; /* number of thunks needed */
uint32_t max_thunks; /* maximum number of thunks */
call_thunk_t *thunks; /* thunk array */
cell_t cur_func; /* current func pcode offset */
/* Options */
int profile; /* profiling flags */
int inline_level; /* inline optimization level */
/* Per-compilation properties */
unsigned int func_idx; /* current function index */
};
class Compiler
{
public:
Compiler(BaseRuntime *rt, cell_t pcode_offs);
~Compiler();
JitFunction *emit(int *errp);
private:
bool setup(cell_t pcode_offs);
bool emitOp(OPCODE op);
cell_t readCell();
private:
Label *labelAt(size_t offset);
bool emitCall();
bool emitNativeCall(OPCODE op);
bool emitSwitch();
void emitGenArray(bool autozero);
void emitCallThunks();
void emitCheckAddress(Register reg);
void emitErrorPath(Label *dest, int code);
void emitErrorPaths();
private:
AssemblerX86 masm;
BaseRuntime *rt_;
const sp_plugin_t *plugin_;
int error_;
uint32_t pcode_start_;
cell_t *code_start_;
cell_t *cip_;
cell_t *code_end_;
Label *jump_map_;
// Errors
Label error_bounds_;
Label error_heap_low_;
Label error_heap_min_;
Label error_stack_low_;
Label error_stack_min_;
Label error_divide_by_zero_;
Label error_memaccess_;
Label error_integer_overflow_;
Label extern_error_;
ke::Vector<CallThunk *> thunks_; //:TODO: free
};
class JITX86
{
public:
JITX86();
public:
bool InitializeJIT();
void ShutdownJIT();
ICompilation *StartCompilation(BaseRuntime *runtime);
ICompilation *StartCompilation();
void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
void FreeContextVars(sp_context_t *ctx);
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 */
public:
JITX86();
public:
bool InitializeJIT();
void ShutdownJIT();
ICompilation *StartCompilation(BaseRuntime *runtime);
ICompilation *StartCompilation();
void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
void FreeContextVars(sp_context_t *ctx);
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:
ExternalAddress GetGenArrayIntrinsic() {
return ExternalAddress(m_pJitGenArray);
}
ExternalAddress GetUniversalReturn() {
return ExternalAddress(m_pJitReturn);
}
void *AllocCode(size_t size);
void FreeCode(void *code);
private:
void *m_pJitEntry; /* Entry function */
void *m_pJitReturn; /* Universal return address */
void *m_pJitGenArray; /* Generates an array */
};
cell_t NativeCallback(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);
const Register pri = eax;
const Register alt = edx;
const Register stk = edi;
const Register dat = ebp;
const Register tmp = ecx;
const Register info = esi;
const Register frm = ebx;
#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_NUM_INFO_VARS 9
#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
#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 Knight::KeCodeCache *g_pCodeCache;
extern JITX86 g_Jit;
-706
View File
@@ -1,706 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include "jit_x86.h"
#include "opcode_helpers.h"
#include "x86_macros.h"
jitoffs_t Write_Execute_Function(JitWriter *jit)
{
/**
* The variables we're passed in:
* void *vars[], void *entry_func
*/
/**
* !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);
/* 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);
/* 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+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+NSTACK] ;restore stack pointer
IA32_Mov_Reg_Rm_Disp8(jit, REG_ESP, REG_ESI, AMX_INFO_NSTACK);
/* Restore SP */
//mov ecx, [esi+CONTEXT]
//sub edi, ebp
//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_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
//pop ebx
//pop edi
//pop esi
//pop ebp
//ret
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_GetError(JitWriter *jit)
{
//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, g_Jit.GetReturnPoint());
}
void Write_SetError(JitWriter *jit, int error)
{
//mov eax, <error>
//jmp [jit_return]
IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
}
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_Rel(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_Rel(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_Rel(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_Rel(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_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
}
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
{
/* :TODO: Should this be checking for below heaplow?
* The old JIT did not.
*/
/**
* :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->mem_size);
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;
//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_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
IA32_Send_Jump8_Here(jit, jmp);
}
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);
/* 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);
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
/* 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_Rel(jit, CC_NZ, data->jit_extern_error);
/* restore what we damaged */
//mov esp, ebx
//pop ebx
//add edi, ebp
//pop edx
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);
//ret
IA32_Return(jit);
}
typedef struct array_creation_s
{
const cell_t *dim_list; /* Dimension sizes */
cell_t dim_count; /* Number of dimensions */
cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
cell_t *base; /* array base */
} array_creation_t;
cell_t _GenerateArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
{
cell_t write_offs = cur_offs;
cell_t *data_offs = ar->data_offs;
cur_offs += ar->dim_list[dim];
/**
* Dimension n-x where x > 2 will have sub-vectors.
* Otherwise, we just need to reference the data section.
*/
if (ar->dim_count > 2 && dim < ar->dim_count - 2)
{
/**
* For each index at this dimension, write offstes to our sub-vectors.
* After we write one sub-vector, we generate its sub-vectors recursively.
* At the end, we're given the next offset we can use.
*/
for (int i = 0; i < ar->dim_list[dim]; i++)
{
ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
write_offs++;
cur_offs = _GenerateArrayIndirectionVectors(ar, dim + 1, cur_offs);
}
} else {
/**
* In this section, there are no sub-vectors, we need to write offsets
* to the data. This is separate so the data stays in one big chunk.
* The data offset will increment by the size of the last dimension,
* because that is where the data is finally computed as.
*/
for (int i = 0; i < ar->dim_list[dim]; i++)
{
ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
write_offs++;
*data_offs = *data_offs + ar->dim_list[dim + 1];
}
}
return cur_offs;
}
static cell_t calc_indirection(const array_creation_t *ar, cell_t dim)
{
cell_t size = ar->dim_list[dim];
if (dim < ar->dim_count - 2)
{
size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
}
return size;
}
void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
{
array_creation_t ar;
cell_t data_offs;
/* Reverse the dimensions */
cell_t dim_list[sDIMEN_MAX];
int cur_dim = 0;
for (int i = _dimcount - 1; i >= 0; i--)
{
dim_list[cur_dim++] = dims[i];
}
ar.base = arraybase;
ar.dim_list = dim_list;
ar.dim_count = _dimcount;
ar.data_offs = &data_offs;
data_offs = calc_indirection(&ar, 0);
_GenerateArrayIndirectionVectors(&ar, 0, 0);
}
/**
* 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)
{
jitoffs_t err1, err2;
/**
* 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, [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_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);
err2 = IA32_Jump_Cond_Imm32(jit, CC_AE, 0);
/* 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);
//: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)
{
/* 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, (void *)JIT_VerifyOrAllocateTracker);
/* Check for errors */
//cmp eax, 0
//jnz :error
IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
/* Restore */
//pop eax
IA32_Pop_Reg(jit, REG_EAX);
/* 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);
}
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
{
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
{
return SP_ERROR_TRACKER_BOUNDS;
}
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)
{
return SP_ERROR_TRACKER_BOUNDS;
}
trk->pCur = trk->pBase + disp;
}
return SP_ERROR_NONE;
}
int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
{
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
if (trk->pCur <= trk->pBase)
{
return SP_ERROR_TRACKER_BOUNDS;
}
return SP_ERROR_NONE;
}
void AlignMe(JitWriter *jit)
{
jitoffs_t cur_offs = jit->get_outputpos();
jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
if (offset)
{
for (jit_uint32_t i=0; i<offset; i++)
{
jit->write_ubyte(IA32_INT3);
}
}
}
-317
View File
@@ -1,317 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#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_C_Function(JitWriter *jit);
/**
* Write the GENARRAY intrinsic function.
*/
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.
* 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);
/**
* 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,
*/
int JIT_VerifyLowBoundTracker(sp_context_t *ctx);
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
/**
* Writes the push into tracker function.
*/
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg);
/**
* Writes the rounding table for the float compare opcode.
*/
void Write_RoundingTable(JitWriter *jit);
/**
* Aligns the current code position to 16 bytes.
*/
void AlignMe(JitWriter *jit);
/**
* 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, //VERIFIED
OP_LREF_ALT, //~VERIFIED
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, //VERIFIED
OP_SREF_ALT, //~VERIFIED
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_STRADJUST_PRI, //VERIFIED
OP_STACKADJUST, //:TODO: VERIFY
OP_ENDPROC, //VERIFIED
OP_FABS, //VERIFIED
OP_FLOAT, //VERIFIED
OP_FLOATADD, //VERIFIED
OP_FLOATSUB, //VERIFIED
OP_FLOATMUL, //VERIFIED
OP_FLOATDIV, //VERIFIED
OP_RND_TO_NEAREST, //VERIFIED
OP_RND_TO_FLOOR, //VERIFIED
OP_RND_TO_CEIL, //VERIFIED
OP_RND_TO_ZERO, //VERIFIED
OP_FLOATCMP, //VERIFIED
/* ----- */
OP_NUM_OPCODES
} OPCODE;
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
-779
View File
@@ -1,779 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
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:
{
WriteOp_Sysreq_N(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;
}
case OP_STRADJUST_PRI:
{
WriteOp_Stradjust_Pri(jit);
break;
}
case OP_FABS:
{
WriteOp_FloatAbs(jit);
break;
}
case OP_FLOAT:
{
WriteOp_Float(jit);
break;
}
case OP_FLOATADD:
{
WriteOp_FloatAdd(jit);
break;
}
case OP_FLOATSUB:
{
WriteOp_FloatSub(jit);
break;
}
case OP_FLOATMUL:
{
WriteOp_FloatMul(jit);
break;
}
case OP_FLOATDIV:
{
WriteOp_FloatDiv(jit);
break;
}
case OP_RND_TO_NEAREST:
{
WriteOp_RountToNearest(jit);
break;
}
case OP_RND_TO_FLOOR:
{
WriteOp_RoundToFloor(jit);
break;
}
case OP_RND_TO_ZERO:
{
WriteOp_RoundToZero(jit);
break;
}
case OP_RND_TO_CEIL:
{
WriteOp_RoundToCeil(jit);
break;
}
case OP_FLOATCMP:
{
WriteOp_FloatCompare(jit);
break;
}
case OP_STACKADJUST:
{
WriteOp_StackAdjust(jit);
break;
}
case OP_ENDPROC:
{
WriteOp_EndProc(jit);
break;
}
#if defined USE_UNGEN_OPCODES
#include "ungen_opcode_switch.inc"
#endif
default:
{
data->error_set = SP_ERROR_INVALID_INSTRUCTION;
break;
}
-121
View File
@@ -1,121 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
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;
}
-325
View File
@@ -1,325 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#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_