added DLL exports (it builds now!)

rewrote error checking mechanism
fixed some opcode cases not being right
fixed various opcode and codegen bugs
fixed stack alignment problems
made proc aligned to a dword
fixed up helpers naming scheme
started marking opcodes as either working or not working
probably more -- too much to list

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40110
This commit is contained in:
David Anderson 2006-10-10 01:55:08 +00:00
parent bc22a3bc84
commit 4b6c4f11af
9 changed files with 736 additions and 452 deletions

View File

@ -42,7 +42,7 @@ public:
}
inline void write_ubyte(jit_uint8_t c)
{
if (outptr)
if (outbase)
{
*outptr = c;
}
@ -50,7 +50,7 @@ public:
}
inline void write_byte(jit_int8_t c)
{
if (outptr)
if (outbase)
{
*outptr = c;
}
@ -58,7 +58,7 @@ public:
}
inline void write_int32(jit_int32_t c)
{
if (outptr)
if (outbase)
{
*(jit_int32_t *)outptr = c;
}
@ -66,21 +66,21 @@ public:
}
inline void write_uint32(jit_uint32_t c)
{
if (outptr)
if (outbase)
{
*(jit_uint32_t *)outptr = c;
}
outptr += sizeof(jit_uint32_t);
}
inline jitoffs_t jit_curpos()
inline jitoffs_t get_outputpos()
{
return (outptr - outbase);
}
inline void setpos(jitoffs_t offs)
inline void set_outputpos(jitoffs_t offs)
{
outptr = outbase + offs;
}
inline jitoffs_t inputrel()
inline jitoffs_t get_inputpos()
{
return (jitoffs_t)((char *)inptr - (char *)inbase);
}

View File

@ -1 +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 0;
}
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;
}

View File

@ -3,6 +3,14 @@
#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_

View File

@ -37,9 +37,11 @@ inline void WriteOp_Push(JitWriter *jit)
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
//optimize encoding a bit...
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
}
IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
}
@ -219,13 +221,31 @@ inline void WriteOp_Sub_Alt(JitWriter *jit)
inline void WriteOp_Proc(JitWriter *jit)
{
/* align this to four byte boundaries!
* This is a decent optimization - x86 likes calls to be properly aligned, otherwise there's an alignment exception
* Since all calls are jumped to by relocation, the nops/garbage will never be hit by the runtime process.
* Just in case, we guard this memory with INT3 to break into the debugger.
*/
jitoffs_t cur_offs = jit->get_outputpos();
if (cur_offs % 4)
{
cur_offs = 4 - (cur_offs % 4);
for (unsigned int i=0; i<cur_offs; i++)
{
jit->write_ubyte(IA32_INT3);
}
/* add this amt to the offset we relocated */
jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t);
jitcode_t rebase = ((CompData *)jit->data)->rebase;
*(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos();
}
//push old frame on stack:
//sub edi, 4
//mov ecx, [esi+frm]
//mov [edi], ecx
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
//mov [edi-4], ecx
//sub edi, 8 ;extra un-used slot for non-existant CIP
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4);
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
//save frame:
//:TODO: move to a temp reg, subtract and then move to mem, faster??
//mov [esi+frm], edi - get new frame
@ -244,7 +264,7 @@ inline void WriteOp_Lidx_B(JitWriter *jit)
//mov eax, [ebp+eax]
IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
Write_Check_VerifyAddr(jit, AMX_REG_PRI, false);
Write_Check_VerifyAddr(jit, AMX_REG_PRI);
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
}
@ -538,9 +558,11 @@ inline void WriteOp_Dec(JitWriter *jit)
//sub [ebp+<val>], 1
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
else
} else {
IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
}
}
inline void WriteOp_Dec_S(JitWriter *jit)
@ -548,9 +570,11 @@ inline void WriteOp_Dec_S(JitWriter *jit)
//sub [ebx+<val>], 1
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
else
} else {
IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
}
}
inline void WriteOp_Dec_I(JitWriter *jit)
@ -564,9 +588,11 @@ inline void WriteOp_Load_Pri(JitWriter *jit)
//mov eax, [ebp+<val>]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
}
}
inline void WriteOp_Load_Alt(JitWriter *jit)
@ -574,9 +600,11 @@ inline void WriteOp_Load_Alt(JitWriter *jit)
//mov edx, [ebp+<val>]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
}
}
inline void WriteOp_Load_S_Pri(JitWriter *jit)
@ -584,9 +612,11 @@ inline void WriteOp_Load_S_Pri(JitWriter *jit)
//mov eax, [ebx+<val>]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
}
}
inline void WriteOp_Load_S_Alt(JitWriter *jit)
@ -594,9 +624,11 @@ inline void WriteOp_Load_S_Alt(JitWriter *jit)
//mov edx, [ebx+<val>]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
}
}
inline void WriteOp_Lref_Pri(JitWriter *jit)
@ -605,9 +637,11 @@ inline void WriteOp_Lref_Pri(JitWriter *jit)
//mov eax, [ebp+eax]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
}
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
}
@ -617,9 +651,11 @@ inline void WriteOp_Lref_Alt(JitWriter *jit)
//mov edx, [ebp+edx]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
}
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
}
@ -629,9 +665,11 @@ inline void WriteOp_Lref_S_Pri(JitWriter *jit)
//mov eax, [ebp+eax]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
}
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
}
@ -641,9 +679,11 @@ inline void WriteOp_Lref_S_Alt(JitWriter *jit)
//mov edx, [ebp+edx]
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
else
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
}
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
}
@ -668,9 +708,11 @@ inline void WriteOp_Addr_Pri(JitWriter *jit)
cell_t val = jit->read_cell();
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
else
} else {
IA32_Add_Eax_Imm32(jit, val);
}
}
inline void WriteOp_Addr_Alt(JitWriter *jit)
@ -680,9 +722,11 @@ inline void WriteOp_Addr_Alt(JitWriter *jit)
cell_t val = jit->read_cell();
IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG);
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG);
else
} else {
IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG);
}
}
inline void WriteOp_Stor_Pri(JitWriter *jit)
@ -690,9 +734,11 @@ inline void WriteOp_Stor_Pri(JitWriter *jit)
//mov [ebp+<val>], eax
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val);
else
} else {
IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val);
}
}
inline void WriteOp_Stor_Alt(JitWriter *jit)
@ -700,9 +746,11 @@ inline void WriteOp_Stor_Alt(JitWriter *jit)
//mov [ebp+<val>], edx
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val);
else
} else {
IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val);
}
}
inline void WriteOp_Stor_S_Pri(JitWriter *jit)
@ -710,9 +758,11 @@ inline void WriteOp_Stor_S_Pri(JitWriter *jit)
//mov [ebx+<val>], eax
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val);
else
} else {
IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val);
}
}
inline void WriteOp_Stor_S_Alt(JitWriter *jit)
@ -720,9 +770,11 @@ inline void WriteOp_Stor_S_Alt(JitWriter *jit)
//mov [ebx+<val>], edx
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val);
else
} else {
IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val);
}
}
inline void WriteOp_Idxaddr(JitWriter *jit)
@ -737,9 +789,11 @@ inline void WriteOp_Sref_Pri(JitWriter *jit)
//mov [ebp+ecx], eax
cell_t 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
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
}
IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
}
@ -749,9 +803,11 @@ inline void WriteOp_Sref_Alt(JitWriter *jit)
//mov [ebp+ecx], edx
cell_t 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
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
}
IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
}
@ -761,9 +817,11 @@ inline void WriteOp_Sref_S_Pri(JitWriter *jit)
//mov [ebp+ecx], eax
cell_t 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
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
}
IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
}
@ -773,9 +831,11 @@ inline void WriteOp_Sref_S_Alt(JitWriter *jit)
//mov [ebp+ecx], edx
cell_t 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
} else {
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
}
IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
}
@ -901,7 +961,8 @@ inline void WriteOp_Heap_Pri(JitWriter *jit)
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP);
Write_CheckMargin_Heap(jit);
/* :TODO: should we do a full bounds check here? */
Write_CheckHeap_Min(jit);
}
inline void WriteOp_Push_Heap_C(JitWriter *jit)
@ -914,7 +975,7 @@ inline void WriteOp_Push_Heap_C(JitWriter *jit)
IA32_Mov_RmEBP_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val);
IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP);
Write_CheckMargin_Heap(jit);
Write_CheckHeap_Low(jit);
}
inline void WriteOp_Pop_Heap_Pri(JitWriter *jit)
@ -926,13 +987,13 @@ inline void WriteOp_Pop_Heap_Pri(JitWriter *jit)
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_TMP, NOSCALE);
Write_CheckMargin_Heap(jit);
Write_CheckHeap_Min(jit);
}
inline void WriteOp_Load_Both(JitWriter *jit)
{
WriteOp_Const_Pri(jit);
WriteOp_Const_Alt(jit);
WriteOp_Load_Pri(jit);
WriteOp_Load_Alt(jit);
}
inline void WriteOp_Load_S_Both(JitWriter *jit)
@ -970,14 +1031,14 @@ inline void WriteOp_Const_S(JitWriter *jit)
inline void WriteOp_Load_I(JitWriter *jit)
{
//mov eax, [ebp+eax]
Write_Check_VerifyAddr(jit, AMX_REG_PRI, false);
Write_Check_VerifyAddr(jit, AMX_REG_PRI);
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
}
inline void WriteOp_Stor_I(JitWriter *jit)
{
//mov [ebp+edx], eax
Write_Check_VerifyAddr(jit, AMX_REG_ALT, false);
Write_Check_VerifyAddr(jit, AMX_REG_ALT);
IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
}
@ -986,24 +1047,34 @@ inline void WriteOp_Lidx(JitWriter *jit)
//lea eax, [edx+4*eax]
//mov eax, [ebp+eax]
IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
Write_Check_VerifyAddr(jit, AMX_REG_PRI, false);
Write_Check_VerifyAddr(jit, AMX_REG_PRI);
IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
}
inline void WriteOp_Stack(JitWriter *jit)
{
/* :TODO: Find an instance in the compiler where
* the ALT value from STACK is actually used!
*/
//mov edx, edi
//add edi, <val>
//sub edx, ebp
cell_t val = jit->read_cell();
IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG);
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG);
else
} else {
IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG);
}
IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG);
Write_CheckMargin_Stack(jit);
if (val > 0)
{
Write_CheckStack_Min(jit);
} else if (val < 0) {
Write_CheckStack_Low(jit);
}
}
inline void WriteOp_Heap(JitWriter *jit)
@ -1013,11 +1084,19 @@ inline void WriteOp_Heap(JitWriter *jit)
cell_t val = jit->read_cell();
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
if (val < SCHAR_MAX && val > SCHAR_MIN)
{
IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP);
else
} else {
IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP);
}
Write_CheckMargin_Heap(jit);
/* NOTE: Backwards from op.stack */
if (val > 0)
{
Write_CheckHeap_Low(jit);
} else if (val < 0) {
Write_CheckHeap_Min(jit);
}
}
inline void WriteOp_SDiv(JitWriter *jit)
@ -1048,24 +1127,23 @@ inline void WriteOp_SDiv_Alt(JitWriter *jit)
inline void WriteOp_Retn(JitWriter *jit)
{
//mov ebx, [edi] - get old frm
//mov ecx, [edi+4] - get return eip
//mov ebx, [edi+4] - get old frm
//add edi, 8 - pop stack
//mov [esi+frm], ebx - restore frame pointer
//add ebx, ebp - relocate
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_STK, 4);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4);
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, 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);
//add edi, [edi] - reduce by this # of params
//add edi, 4 - pop one extra for the # itself
IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_STK, MOD_MEM_REG);
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
/* pop params */
//mov ecx, [edi]
//lea edi, [edi+edi*4+4]
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4);
//jmp ecx - jump to return eip
IA32_Jump_Reg(jit, AMX_REG_TMP);
//ret - return (EIP on real stack!)
IA32_Return(jit);
}
inline void WriteOp_Call(JitWriter *jit)
@ -1078,7 +1156,12 @@ inline void WriteOp_Call(JitWriter *jit)
inline void WriteOp_Bounds(JitWriter *jit)
{
Write_BoundsCheck(jit);
cell_t val = jit->read_cell();
//cmp eax, <val>
//ja :error
IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_PRI, val);
IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds);
}
inline void WriteOp_Halt(JitWriter *jit)
@ -1095,14 +1178,7 @@ inline void WriteOp_Halt(JitWriter *jit)
jit->read_cell();
CompData *data = (CompData *)jit->data;
jitoffs_t reloc;
if (data->inline_level & JIT_INLINE_ERRORCHECKS)
{
reloc = IA32_Jump_Imm32(jit, 0);
} else {
reloc = IA32_Call_Imm32(jit, 0);
}
IA32_Write_Jump32(jit, reloc, data->jit_return);
IA32_Jump_Imm32_Abs(jit, data->jit_return);
}
inline void WriteOp_Break(JitWriter *jit)
@ -1112,10 +1188,10 @@ inline void WriteOp_Break(JitWriter *jit)
{
//mov ecx, <cip>
jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0);
jitoffs_t save = jit->jit_curpos();
jit->setpos(wr);
jitoffs_t save = jit->get_outputpos();
jit->set_outputpos(wr);
jit->write_uint32((uint32_t)(jit->outbase + wr));
jit->setpos(save);
jit->set_outputpos(save);
wr = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, wr, data->jit_break);
@ -1126,7 +1202,6 @@ inline void WriteOp_Jump(JitWriter *jit)
{
//jmp <offs>
cell_t amx_offs = jit->read_cell();
IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false));
}
@ -1163,7 +1238,7 @@ inline void WriteOp_Jneq(JitWriter *jit)
//jne <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_NE, RelocLookup(jit, target, false));
IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false));
}
inline void WriteOp_Jsless(JitWriter *jit)
@ -1172,7 +1247,7 @@ inline void WriteOp_Jsless(JitWriter *jit)
//jl <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_L, RelocLookup(jit, target, false));
IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false));
}
inline void WriteOp_Jsleq(JitWriter *jit)
@ -1181,7 +1256,7 @@ inline void WriteOp_Jsleq(JitWriter *jit)
//jle <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_LE, RelocLookup(jit, target, false));
IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false));
}
inline void WriteOp_JsGrtr(JitWriter *jit)
@ -1190,7 +1265,7 @@ inline void WriteOp_JsGrtr(JitWriter *jit)
//jg <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_G, RelocLookup(jit, target, false));
IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false));
}
inline void WriteOp_JsGeq(JitWriter *jit)
@ -1199,7 +1274,7 @@ inline void WriteOp_JsGeq(JitWriter *jit)
//jge <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_GE, RelocLookup(jit, target, false));
IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false));
}
inline void WriteOp_Switch(JitWriter *jit)
@ -1279,10 +1354,10 @@ inline void WriteOp_Switch(JitWriter *jit)
jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG);
IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG);
/* The case table starts here. Go back and write the output pointer. */
jitoffs_t cur_pos = jit->jit_curpos();
jit->setpos(tbl_offs);
jitoffs_t cur_pos = jit->get_outputpos();
jit->set_outputpos(tbl_offs);
jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos));
jit->setpos(cur_pos);
jit->set_outputpos(cur_pos);
//now we can write the case table, finally!
jit_uint32_t base = (jit_uint32_t)jit->outbase;
for (cell_t i=0; i<num_cases; i++)
@ -1308,6 +1383,8 @@ inline void WriteOp_Switch(JitWriter *jit)
IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false));
}
}
//if we get here, there was a bug in the JIT, so we should break into the debugger
jit->write_ubyte(IA32_INT3);
}
}
@ -1321,6 +1398,98 @@ inline void WriteOp_Casetbl(JitWriter *jit)
jit->inptr += num_cases;
}
inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit)
{
/* store the number of parameters on the stack,
* and store the native index as well.
*/
cell_t num_params = jit->read_cell();
cell_t native_index = jit->read_cell();
//mov eax, <num_params>
//mov ecx, <native_index>
IA32_Mov_Rm_Imm32(jit, REG_EAX, num_params, MOD_REG);
IA32_Mov_Rm_Imm32(jit, REG_ECX, native_index, MOD_REG);
jitoffs_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n);
}
inline void WriteOp_Sysreq_N(JitWriter *jit)
{
/* The big daddy of opcodes. */
cell_t num_params = jit->read_cell();
cell_t native_index = jit->read_cell();
CompData *data = (CompData *)jit->data;
/* store the number of parameters on the stack */
//mov [edi-4], num_params
//sub edi, 4
IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4);
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
/* save registers we will need */
//push edx
IA32_Push_Reg(jit, AMX_REG_ALT);
/* push some callback stuff */
//push edi ; stack
//push <native> ; native index
IA32_Push_Reg(jit, AMX_REG_STK);
IA32_Push_Imm32(jit, native_index);
/* Relocate stack, heap, frm information, then store back */
//sub edi, ebp
//mov ecx, [esi+hea]
//mov eax, [esi+context]
//mov [eax+hp], ecx
//mov [eax+sp], edi
//mov ecx, [esi+frm]
//mov [eax+frm], ecx
IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG);
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
//mov eax, [eax+context]
//call NativeCallback
IA32_Push_Reg(jit, REG_EAX);
jitoffs_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback);
/* 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_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Pop_Reg(jit, AMX_REG_ALT);
/* check for errors */
//test eax, eax
//jne :error
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return);
/* pop the 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.
*/
num_params++;
num_params *= 4;
//add edi, <val*4+4>
if (num_params < SCHAR_MAX && num_params > SCHAR_MIN)
{
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG);
} else {
IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG);
}
}
/*************************************************
*************************************************
@ -1329,6 +1498,12 @@ inline void WriteOp_Casetbl(JitWriter *jit)
*************************************************
*************************************************/
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
{
/* :TODO: fill this out... */
return 0;
}
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
{
@ -1340,7 +1515,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
/* The actual offset is EIP relative. We need to relocate it.
* Note that this assumes that we're pointing to the next op.
*/
pcode_offs += jit->inputrel();
pcode_offs += jit->get_inputpos();
}
/* Offset must always be 1)positive and 2)less than the codesize */
assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize);
@ -1416,43 +1591,59 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
* so we can check the exact memory usage.
*/
data->codesize = plugin->pcode_size;
writer.data = data;
writer.inbase = (cell_t *)code;
writer.outptr = NULL;
writer.outbase = NULL;
data->rebase = (jitcode_t *)engine->BaseAlloc(plugin->pcode_size);
data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size);
/* Jump back here for second pass */
jit_rewind:
/* Initialize pass vars */
writer.inptr = writer.inbase;
data->jit_chkmargin_heap = 0;
data->jit_verify_addr_eax = 0;
data->jit_verify_addr_edx = 0;
data->jit_bounds = 0;
/* Start writing the actual code */
data->jit_return = Write_Execute_Function(jit);
/* Write error checking routines in case they are needed */
/* Write error checking routines that are jumped to */
if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
{
jitpos = jit->jit_curpos();
Write_Check_VerifyAddr(jit, REG_EAX, true);
jitpos = jit->get_outputpos();
Write_Check_VerifyAddr(jit, REG_EAX);
data->jit_verify_addr_eax = jitpos;
jitpos = jit->jit_curpos();
Write_Check_VerifyAddr(jit, REG_EDX, true);
jitpos = jit->get_outputpos();
Write_Check_VerifyAddr(jit, REG_EDX);
data->jit_verify_addr_edx = jitpos;
jitpos = jit->jit_curpos();
Write_CheckMargin_Heap(jit);
data->jit_chkmargin_heap = jitpos;
jitpos = jit->jit_curpos();
Write_BoundsCheck(jit);
data->jit_bounds = jitpos;
}
/* Write error codes we need */
{
data->jit_error_divzero = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_DIVIDE_BY_ZERO);
data->jit_error_stacklow = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_STACKLOW);
data->jit_error_stackmin = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_STACKMIN);
data->jit_error_bounds = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_ARRAY_BOUNDS);
data->jit_error_memaccess = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_MEMACCESS);
data->jit_error_heaplow = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_HEAPLOW);
data->jit_error_heapmin = jit->get_outputpos();
Write_SetError(jit, true, SP_ERR_HEAPMIN);
}
/* Actual code generation! */
if (writer.outbase == NULL)
{
/*******
@ -1461,14 +1652,14 @@ jit_rewind:
jitoffs_t pcode_offs;
jitoffs_t native_offs;
for (; writer.inptr <= endptr;)
for (; writer.inptr < endptr;)
{
/* Store the native offset into the rebase memory.
* This large chunk of memory lets us do an instant lookup
* based on an original pcode offset.
*/
pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code);
native_offs = jit->jit_curpos();
native_offs = jit->get_outputpos();
*((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs;
/* Now read the opcode and continue. */
@ -1480,7 +1671,7 @@ jit_rewind:
}
/* the total codesize is now known! */
uint32_t mem = writer.jit_curpos();
uint32_t mem = writer.get_outputpos();
writer.outbase = (jitcode_t)engine->ExecAlloc(mem);
writer.outptr = writer.outbase;
/* go back for third pass */
@ -1489,7 +1680,7 @@ jit_rewind:
/*******
* THIRD PASS - write opcode info
*******/
for (; writer.inptr <= endptr;)
for (; writer.inptr < endptr;)
{
op = (OPCODE)writer.read_cell();
switch (op)
@ -1630,7 +1821,7 @@ const char *JITX86::GetVMName()
int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result)
{
typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *);
CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase;
CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase;
return fn(ctx, code_idx, result);
}
@ -1652,6 +1843,7 @@ ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin)
CompData *data = new CompData;
data->plugin = plugin;
data->inline_level = JIT_INLINE_ERRORCHECKS;
return data;
}

View File

@ -9,28 +9,32 @@ using namespace SourcePawn;
#define JIT_INLINE_ERRORCHECKS (1<<0)
#define JIT_INLINE_NATIVES (1<<1)
#define STACK_MARGIN 16
#define STACK_MARGIN 64 //8 parameters of safety, I guess
class CompData : public ICompilation
{
public:
CompData() : plugin(NULL),
debug(false), inline_level(3), checks(true),
rebase(NULL)
debug(false), inline_level(0), rebase(NULL)
{
};
public:
sp_plugin_t *plugin;
jitcode_t *rebase;
jitcode_t rebase;
jitoffs_t jit_return;
jitoffs_t jit_verify_addr_eax;
jitoffs_t jit_verify_addr_edx;
jitoffs_t jit_chkmargin_heap;
jitoffs_t jit_bounds;
jitoffs_t jit_break;
jitoffs_t jit_sysreq_n;
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;
uint32_t codesize;
int inline_level;
bool checks;
bool debug;
};
@ -48,6 +52,7 @@ public:
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);
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
#define AMX_REG_PRI REG_EAX
@ -65,6 +70,7 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
#define AMX_INFO_CONTEXT 12 //physical
#define AMX_INFO_STACKTOP 16 //relocated
#define AMX_INFO_HEAPLOW 20 //not relocated
#define AMX_INFO_STACKTOP_U 24 //not relocated
extern ISourcePawnEngine *engine;

View File

@ -6,6 +6,8 @@
int OpAdvTable[OP_NUM_OPCODES];
#define NUM_INFO_PARAMS 7
jitoffs_t Write_Execute_Function(JitWriter *jit)
{
/**
@ -20,7 +22,6 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
* This is because we do not support resuming or sleeping!
*/
//:TODO: FIX THIS FOR THE EBP AND EDI SWITCHING
//push ebp
//mov ebp, esp
IA32_Push_Reg(jit, REG_EBP);
@ -33,9 +34,9 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
IA32_Push_Reg(jit, REG_EDI);
IA32_Push_Reg(jit, REG_EBX);
//sub esp, 4*6 - allocate info array
//sub esp, 4*n - reserve info array
//mov esi, esp - save info pointer
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG);
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 */
@ -45,7 +46,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
//mov [esi+12], eax - store context into info pointer
//mov ecx, [eax+<offs>] - get heap pointer
//mov [esi+4], ecx - store heap into info pointer
//mov edi, [eax+<offs>] - get data pointer
//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);
@ -55,76 +56,73 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data));
/* Frame setup */
//mov ebp, [eax+<offs>] - get stack pointer
//add ebp, edi - relocate to data section
//mov ebx, ebp - copy sp to frm
//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, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
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, edi - copy base of data to temp var
//add ecx, [eax+<offs>] - add memsize to get stack top
//mov [esi+16], ecx - store stack top into info pointer
//mov ecx, [eax+<offs>] - copy memsize to temp var
//mov [esi+x], ecx - store unrelocated
//add ecx, ebp - relocate
//mov [esi+x], ecx - store relocated
//mov ecx, [eax+<offs>] - get heap low
//mov [esi+20], ecx - store heap low into info pointer
IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG);
IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U);
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);
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase));
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW);
/* Remaining needed vars */
//mov ecx, [ebp+12] - get code index
//add ecx, [eax+<offs>] - add code base to index
//mov edx, [eax+<offs>] - get alt
//mov eax, [eax+<offs>] - get pri
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12);
//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));
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt));
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri));
/* by now, everything is set up, so we can call into the plugin */
//call ecx
IA32_Call_Reg(jit, REG_ECX);
/* if the code flow gets to here, there was a normal return */
//mov ebp, [esi+8] - get retval pointer
//mov [ebp], eax - store retval from PRI
//mov ecx, [esi+8] - get retval pointer
//mov [ecx], eax - store retval from PRI
//mov eax, SP_ERR_NONE - set no error
IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL);
IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG);
IA32_Mov_Reg_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_ERR_NONE);
/* save where error checking/halting functions should go to */
jitoffs_t offs_return;
CompData *data = (CompData *)jit->data;
if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
{
/* We have to write code assume we're breaking out of a call */
//jmp [past the next instruction]
//add esp, 4
jitoffs_t offs = IA32_Jump_Imm8(jit, 0);
offs_return = jit->jit_curpos();
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
IA32_Send_Jump8_Here(jit, offs);
} else {
offs_return = jit->jit_curpos();
}
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 _not_ going to restore anything that was on the stack.
* This is a tiny, useless optimization based on the fact that
* BaseContext::Execute() automatically restores our values anyway.
/* _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(jit, REG_ECX, REG_EDX, MOD_REG);
//add esp, 4*6
//add esp, 4*NUM_INFO_PARAMS
//pop ebx
//pop edi
//pop esi
//pop ebp
//ret
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG);
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);
@ -167,7 +165,7 @@ void Write_BreakDebug(JitWriter *jit)
IA32_Return(jit);
}
void Write_Error(JitWriter *jit, int error)
void Write_SetError(JitWriter *jit, bool always_inline, int error)
{
CompData *data = (CompData *)jit->data;
@ -182,22 +180,67 @@ void Write_Error(JitWriter *jit, int error)
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
{
//test reg, reg
//jnz :continue
//divzero: (write error)
//jz :error
IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS))
{
//sub esp, 4 - correct stack for returning to non-inlined JIT
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
}
Write_Error(jit, SP_ERR_DIVIDE_BY_ZERO);
//continue:
IA32_Send_Jump8_Here(jit, jmp);
IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
}
//:TODO: FIX THIS FOR NEW EBP STUFF
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall)
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;
@ -205,182 +248,57 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall)
* The old JIT did not.
*/
if (!data->checks)
{
return;
}
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 (!firstcall)
if ((reg == REG_EAX) && data->jit_verify_addr_eax)
{
jitoffs_t call = IA32_Call_Imm32(jit, 0);
if (reg == REG_EAX)
{
IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
} else if (reg == REG_EDX) {
IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
}
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;
} else if (firstcall) {
/* Inline + initial gen == no code */
return;
}
//cmp reg, [stp]
//jae memaccess
//cmp reg, [hea]
//jb continue
//lea ecx, [reg+edi]
//cmp ecx, ebp
//jae continue
//memaccess: (write error)
//continue:
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP);
jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
/**
* :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>, [esi+info.stpu]
//jae :error
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP_U);
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);
jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
IA32_Lea_Reg_DispRegMult(jit, AMX_REG_TMP, reg, AMX_REG_DAT, NOSCALE);
IA32_Cmp_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
IA32_Send_Jump8_Here(jit, jmp1);
Write_Error(jit, SP_ERR_MEMACCESS);
IA32_Send_Jump8_Here(jit, jmp2);
IA32_Send_Jump8_Here(jit, jmp3);
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 Write_BoundsCheck(JitWriter *jit)
{
CompData *data = (CompData *)jit->data;
bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS);
/* :TODO: break out on high -O level? */
if (!always_inline)
{
if (data->jit_bounds)
{
/* just generate the call */
//mov ecx, <val>
//call <offs>
IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit->read_cell());
jitoffs_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, call, data->jit_bounds);
} else {
//cmp eax, 0
//jl :err_bounds
//cmp eax, ecx
//jg :err_bounds
//ret
IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0);
jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
//:TODO: make sure this is right order
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG);
jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
IA32_Return(jit);
IA32_Send_Jump8_Here(jit, jmp1);
IA32_Send_Jump8_Here(jit, jmp2);
Write_Error(jit, SP_ERR_ARRAY_BOUNDS);
}
} else {
//cmp eax, 0
//jl :err_bounds
IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0);
jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
//cmp eax, <val>
//jg :err_bounds
cell_t val = jit->read_cell();
if (val < SCHAR_MAX && val > SCHAR_MIN)
IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
else
IA32_Cmp_Eax_Imm32(jit, val);
jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
//jmp :continue
jitoffs_t cont = IA32_Jump_Imm8(jit, 0);
//:err_bounds
IA32_Send_Jump8_Here(jit, jmp1);
IA32_Send_Jump8_Here(jit, jmp2);
Write_Error(jit, SP_ERR_ARRAY_BOUNDS);
//:continue
IA32_Send_Jump8_Here(jit, cont);
}
}
void Write_CheckMargin_Heap(JitWriter *jit)
{
CompData *data = (CompData *)jit->data;
bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS);
if (!always_inline && data->jit_chkmargin_heap)
{
/* just generate the call */
jitoffs_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, call, data->jit_chkmargin_heap);
} else {
//mov ecx, [esi+hea]
//cmp ecx, [esi+hlw]
//jl :error_heapmin
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW);
jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
//lea ecx, [ebp+ecx+STACK_MARGIN]
//cmp ecx, edi
// jg :error_heaplow
//OR
// ret
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);
jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
jitoffs_t cont;
if (always_inline)
{
cont = IA32_Jump_Imm8(jit, 0);
} else {
IA32_Return(jit);
}
//:error_heapmin
IA32_Send_Jump8_Here(jit, hm);
Write_Error(jit, SP_ERR_HEAPMIN);
//:error_heaplow
IA32_Send_Jump8_Here(jit, hl);
Write_Error(jit, SP_ERR_HEAPLOW);
//:continue
if (!always_inline)
{
IA32_Send_Jump8_Here(jit, cont);
}
}
}
void Write_CheckMargin_Stack(JitWriter *jit)
{
/* this is small, so we always inline it.
*/
//cmp edi, [esi+stp]
//jle :continue
IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0);
if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS))
{
//sub esp, 4 - correct stack for returning to non-inlined JIT
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
}
Write_Error(jit, SP_ERR_STACKMIN);
//continue:
IA32_Send_Jump8_Here(jit, jmp);
}
void Macro_PushN_Addr(JitWriter *jit, int i)
{
//push eax
@ -404,6 +322,7 @@ void Macro_PushN_Addr(JitWriter *jit, int i)
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);
//:TODO: fix the case of this size > imm8!
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
IA32_Pop_Reg(jit, AMX_REG_PRI);
}
@ -464,6 +383,83 @@ void Macro_PushN(JitWriter *jit, int i)
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
}
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 */
//sub edi, ebp
//mov ecx, [esi+hea]
//mov eax, [esi+context]
//mov [eax+hp], ecx
//mov [eax+sp], edi
//mov ecx, [esi+frm]
//mov [eax+frm], ecx
IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG);
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
//mov eax, [eax+context]
//call NativeCallback
IA32_Push_Reg(jit, REG_EAX);
jitoffs_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback);
/* 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_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
IA32_Pop_Reg(jit, AMX_REG_ALT);
IA32_Pop_Reg(jit, REG_ECX);
//Note: always safe, we're in a call
//test eax, eax
//jne :error
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return);
/* 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);
}
JITX86::JITX86()
{
memset(OpAdvTable, -1, sizeof(OpAdvTable));
@ -643,5 +639,4 @@ JITX86::JITX86()
OpAdvTable[OP_JLEQ] = -3;
OpAdvTable[OP_JGRTR] = -3;
OpAdvTable[OP_JGEQ] = -3;
}

View File

@ -10,39 +10,41 @@
*/
jitoffs_t Write_Execute_Function(JitWriter *jit);
/**
* Writes the Sysreq.n opcode as a function call.
*/
void WriteOp_Sysreq_N_Function(JitWriter *jit);
/**
* Generates code to set an error state in the VM and return.
* Note that this should only be called from inside an error
* checking function.
* This is used for generating the error set points in the VM.
*/
void Write_Error(JitWriter *jit, int error);
void Write_SetError(JitWriter *jit, bool always_inline, int error);
/**
* Verifies an address by register.
* :TODO: optimize and make it look like the heap checkfunction!
* Checks the stacks for min and low errors.
* :TODO: Should a variation of this go in the pushN opcodes?
*/
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall);
void Write_CheckStack_Min(JitWriter *jit);
void Write_CheckStack_Low(JitWriter *jit);
/**
* Verifies stack margins.
* Checks the heap for min and low errors.
*/
void Write_CheckMargin_Stack(JitWriter *jit);
void Write_CheckHeap_Min(JitWriter *jit);
void Write_CheckHeap_Low(JitWriter *jit);
/**
* Verifies heap margins.
/**
* Verifies an address by register. The address must reside
* between DAT and HP and SP and STP.
*/
void Write_CheckMargin_Heap(JitWriter *jit);
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 a bounds check.
*/
void Write_BoundsCheck(JitWriter *jit);
/**
* Writes the break debug function.
*/
@ -56,132 +58,147 @@ void Macro_PushN_S(JitWriter *jit, int i);
void Macro_PushN_C(JitWriter *jit, int i);
void Macro_PushN(JitWriter *jit, int i);
/**
* 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, //DONE
OP_LOAD_ALT, //DONE
OP_LOAD_S_PRI, //DONE
OP_LOAD_S_ALT, //DONE
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, //DONE
OP_LREF_S_ALT, //DONE
OP_LOAD_I, //DONE
OP_LREF_S_PRI, //VERIFIED
OP_LREF_S_ALT, //~VERIFIED (lref.s.pri)
OP_LOAD_I, //VERIFIED
OP_LODB_I, // !GEN :TODO: - only used for pack access - drop support in compiler first
OP_CONST_PRI, //DONE
OP_CONST_ALT, //DONE
OP_ADDR_PRI, //DONE
OP_ADDR_ALT, //DONE
OP_STOR_PRI, //DONE
OP_STOR_ALT, //DONE
OP_STOR_S_PRI, //DONE
OP_STOR_S_ALT, //DONE
OP_SREF_PRI, //DONE
OP_SREF_ALT, //DONE
OP_SREF_S_PRI, // !GEN :TODO: we will need this for dynarrays
OP_SREF_S_ALT, // !GEN :TODO: we will need this for dynarrays
OP_STOR_I, //DONE
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, // !GEN :TODO: - only used for pack access, drop support in compiler first
OP_LIDX, //DONE
OP_LIDX, //VERIFIED
OP_LIDX_B, //DONE
OP_IDXADDR, //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, //DONE
OP_MOVE_ALT, //DONE
OP_MOVE_ALT, //VERIFIED
OP_XCHG, //DONE
OP_PUSH_PRI, //DONE
OP_PUSH_ALT, //DONE
OP_PUSH_R, // !GEN DEPRECATED
OP_PUSH_C, //DONE
OP_PUSH_C, //VERIFIED
OP_PUSH, //DONE
OP_PUSH_S, //DONE
OP_POP_PRI, //DONE
OP_POP_ALT, //DONE
OP_STACK, //DONE
OP_PUSH_S, //VERIFIED
OP_POP_PRI, //VERIFIED
OP_POP_ALT, //VERIFIED
OP_STACK, //VERIFIED
OP_HEAP, //DONE
OP_PROC, //DONE
OP_PROC, //VERIFIED
OP_RET, // !GEN
OP_RETN, //DONE
OP_CALL, //DONE
OP_RETN, //VERIFIED
OP_CALL, //VERIFIED
OP_CALL_PRI, // !GEN
OP_JUMP, //DONE
OP_JUMP, //VERIFIED
OP_JREL, // !GEN
OP_JZER, //DONE
OP_JZER, //VERIFIED
OP_JNZ, //DONE
OP_JEQ, //DONE
OP_JNEQ, //DONE
OP_JEQ, //VERIFIED
OP_JNEQ, //VERIFIED
OP_JLESS, // !GEN
OP_JLEQ, // !GEN
OP_JGRTR, // !GEN
OP_JGEQ, // !GEN
OP_JSLESS, //DONE
OP_JSLEQ, //DONE
OP_JSGRTR, //DONE
OP_JSGEQ, //DONE
OP_SHL, //DONE
OP_SHR, //DONE
OP_SSHR, //DONE
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, //DONE
OP_SMUL, //VERIFIED
OP_SDIV, //DONE
OP_SDIV_ALT, //DONE
OP_SDIV_ALT, //VERIFIED
OP_UMUL, // !GEN
OP_UDIV, // !GEN
OP_UDIV_ALT, // !GEN
OP_ADD, //DONE
OP_ADD, //VERIFIED
OP_SUB, //DONE
OP_SUB_ALT, //DONE
OP_AND, //DONE
OP_OR, //DONE
OP_XOR, //DONE
OP_NOT, //DONE
OP_NEG, //DONE
OP_INVERT, //DONE
OP_ADD_C, //DONE
OP_SMUL_C, //DONE
OP_ZERO_PRI, //DONE
OP_ZERO_ALT, //DONE
OP_ZERO, //DONE
OP_ZERO_S, //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, //DONE
OP_NEQ, //DONE
OP_EQ, //VERIFIED
OP_NEQ, //VERIFIED
OP_LESS, // !GEN
OP_LEQ, // !GEN
OP_GRTR, // !GEN
OP_GEQ, // !GEN
OP_SLESS, //DONE
OP_SLEQ, //DONE
OP_SGRTR, //DONE
OP_SGEQ, //DONE
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, //DONE
OP_INC_ALT, //DONE
OP_INC, //DONE
OP_INC_S, //DONE
OP_INC_I, //DONE
OP_DEC_PRI, //DONE
OP_DEC_ALT, //DONE
OP_DEC, //DONE
OP_DEC_S, //DONE
OP_DEC_I, //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, //DONE
OP_CMPS, // !GEN
OP_FILL, //DONE
OP_FILL, //VERIFIED
OP_HALT, //DONE
OP_BOUNDS, //DONE
OP_BOUNDS, //VERIFIED
OP_SYSREQ_PRI, // !GEN
OP_SYSREQ_C,
OP_SYSREQ_C, // !GEN DEPRECATED
OP_FILE, // !GEN DEPRECATED
OP_LINE, // !GEN DEPRECATED
OP_SYMBOL, // !GEN DEPRECATED
@ -189,32 +206,32 @@ typedef enum
OP_JUMP_PRI, // !GEN
OP_SWITCH, //DONE
OP_CASETBL, //DONE
OP_SWAP_PRI, //DONE
OP_SWAP_ALT, //DONE
OP_PUSH_ADR, //DONE
OP_NOP, //DONE
OP_SWAP_PRI, //VERIFIED
OP_SWAP_ALT, //~VERIFIED (swap.alt)
OP_PUSH_ADR, //VERIFIED
OP_NOP, //VERIFIED (lol)
OP_SYSREQ_N,
OP_SYMTAG, // !GEN DEPRECATED
OP_BREAK, //DONE
OP_PUSH2_C, //DONE
OP_PUSH2, //DONE
OP_PUSH2_S, //DONE
OP_PUSH2_ADR, //DONE
OP_PUSH3_C, //DONE
OP_PUSH3, //DONE
OP_PUSH3_S, //DONE
OP_PUSH3_ADR, //DONE
OP_PUSH4_C, //DONE
OP_PUSH4, //DONE
OP_PUSH4_S, //DONE
OP_PUSH4_ADR, //DONE
OP_PUSH5_C, //DONE
OP_PUSH5, //DONE
OP_PUSH5_S, //DONE
OP_PUSH5_ADR, //DONE
OP_LOAD_BOTH, //DONE
OP_LOAD_S_BOTH, //DONE
OP_CONST, //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

View File

@ -30,7 +30,7 @@
}
case OP_PUSH3_C:
{
WriteOp_Push3(jit);
WriteOp_Push3_C(jit);
break;
}
case OP_PUSH4_C:
@ -350,12 +350,12 @@
}
case OP_LREF_S_PRI:
{
WriteOp_Lref_Pri(jit);
WriteOp_Lref_S_Pri(jit);
break;
}
case OP_LREF_S_ALT:
{
WriteOp_Lref_Alt(jit);
WriteOp_Lref_S_Alt(jit);
break;
}
case OP_CONST_PRI:
@ -613,6 +613,16 @@
WriteOp_Jsless(jit);
break;
}
case OP_JSGRTR:
{
WriteOp_JsGrtr(jit);
break;
}
case OP_JSGEQ:
{
WriteOp_JsGeq(jit);
break;
}
case OP_JSLEQ:
{
WriteOp_Jsleq(jit);

View File

@ -117,6 +117,7 @@
#define IA32_POP_REG 0x58 // encoding is +r
#define IA32_PUSH_REG 0x50 // encoding is +r
#define IA32_PUSH_RM 0xFF // encoding is /6
#define IA32_PUSH_IMM32 0x68 // encoding is <imm32>
#define IA32_REP 0xF3 // no extra encoding
#define IA32_MOVSD 0xA5 // no extra encoding
#define IA32_MOVSB 0xA4 // no extra encoding
@ -124,6 +125,8 @@
#define IA32_CLD 0xFC // no extra encoding
#define IA32_PUSHAD 0x60 // no extra encoding
#define IA32_POPAD 0x61 // no extra encoding
#define IA32_NOP 0x90 // no extra encoding
#define IA32_INT3 0xCC // no extra encoding
inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm)
{
@ -368,6 +371,13 @@ inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp8);
}
inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
@ -475,7 +485,7 @@ inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit,
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, dest));
jitoffs_t ptr = jit->jit_curpos();
jitoffs_t ptr = jit->get_outputpos();
jit->write_int32(0);
return ptr;
}
@ -599,6 +609,12 @@ inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg)
jit->write_ubyte(IA32_PUSH_REG+reg);
}
inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val)
{
jit->write_ubyte(IA32_PUSH_IMM32);
jit->write_int32(val);
}
inline void IA32_Pushad(JitWriter *jit)
{
jit->write_ubyte(IA32_PUSHAD);
@ -633,6 +649,14 @@ inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_REG_MEM);
@ -732,7 +756,7 @@ inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_
{
jitoffs_t offs;
jit->write_ubyte(IA32_MOV_REG_IMM+dest);
offs = jit->jit_curpos();
offs = jit->get_outputpos();
jit->write_int32(num);
return offs;
}
@ -787,7 +811,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM+cond);
ptr = jit->jit_curpos();
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
@ -796,7 +820,7 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM32);
ptr = jit->jit_curpos();
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
@ -805,7 +829,7 @@ inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM8);
ptr = jit->jit_curpos();
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
@ -815,7 +839,7 @@ inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int3
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM32_1);
jit->write_ubyte(IA32_JCC_IMM32_2+cond);
ptr = jit->jit_curpos();
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
@ -836,7 +860,7 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_CALL_IMM32);
ptr = jit->jit_curpos();
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
@ -878,7 +902,7 @@ inline void IA32_Jump_Imm32_Abs(JitWriter *jit, jitoffs_t target)
{
/* :TODO: this should work, but does it? */
jit->write_ubyte(IA32_JMP_IMM32);
IA32_Write_Jump32(jit, jit->jit_curpos(), target);
IA32_Write_Jump32(jit, jit->get_outputpos(), target);
jit->outptr += 4;
}
@ -887,19 +911,19 @@ inline void IA32_Jump_Cond_Imm32_Abs(JitWriter *jit, jit_uint8_t cond, jitoffs_t
/* :TODO: this should work, but does it? */
jit->write_ubyte(IA32_JCC_IMM32_1);
jit->write_ubyte(IA32_JCC_IMM32_2+cond);
IA32_Write_Jump32(jit, jit->jit_curpos(), target);
IA32_Write_Jump32(jit, jit->get_outputpos(), target);
jit->outptr += 4;
}
inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp)
{
jitoffs_t curptr = jit->jit_curpos();
jitoffs_t curptr = jit->get_outputpos();
IA32_Write_Jump8(jit, jmp, curptr);
}
inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp)
{
jitoffs_t curptr = jit->jit_curpos();
jitoffs_t curptr = jit->get_outputpos();
IA32_Write_Jump32(jit, jmp, curptr);
}