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:
parent
bc22a3bc84
commit
4b6c4f11af
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user