diff -r 7602d7fb60d9 -r 026da5437111 sourcepawn/jit/x86/jit_x86.cpp --- a/sourcepawn/jit/x86/jit_x86.cpp Fri Jul 11 06:51:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3049 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include -#include -#include "jit_x86.h" -#include "opcode_helpers.h" -#include -#include "../jit_version.h" -#include "../sp_vm_engine.h" -#include "../engine2.h" -#include "../BaseRuntime.h" -#include "../sp_vm_basecontext.h" - -#if defined USE_UNGEN_OPCODES -#include "ungen_opcodes.h" -#endif - -JITX86 g_Jit1; -ISourcePawnEngine *engine = &g_engine1; - -inline sp_plugin_t *GETPLUGIN(sp_context_t *ctx) -{ - return (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]); -} - -inline void WriteOp_Move_Pri(JitWriter *jit) -{ - //mov eax, edx - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Move_Alt(JitWriter *jit) -{ - //mov edx, eax - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Xchg(JitWriter *jit) -{ - //xchg eax, edx - IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT); -} - -inline void WriteOp_Push(JitWriter *jit) -{ - //push stack, DAT offset based - //sub edi, 4 - //mov ecx, [ebp+] - //mov [edi], ecx - cell_t val = jit->read_cell(); - 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 { - 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); -} - -inline void WriteOp_Push_C(JitWriter *jit) -{ - //push stack - //mov [edi-4], - //sub edi, 4 - cell_t val = jit->read_cell(); - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Zero(JitWriter *jit) -{ - //mov [ebp+], 0 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val); - } -} - -inline void WriteOp_Zero_S(JitWriter *jit) -{ - //mov [ebx+], 0 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val); - } -} - -inline void WriteOp_Push_S(JitWriter *jit) -{ - //push stack, FRM offset based - //sub edi, 4 - //mov ecx, [ebx+] - //mov [edi], ecx - cell_t val = jit->read_cell(); - 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_FRM, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val); - } - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Push_Pri(JitWriter *jit) -{ - //mov [edi-4], eax - //sub edi, 4 - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Push_Alt(JitWriter *jit) -{ - //mov [edi-4], edx - //sub edi, 4 - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Push2_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 2); -} - -inline void WriteOp_Push3_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 3); -} - -inline void WriteOp_Push4_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 4); -} - -inline void WriteOp_Push5_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 5); -} - -inline void WriteOp_Push2_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 2); -} - -inline void WriteOp_Push3_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 3); -} - -inline void WriteOp_Push4_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 4); -} - -inline void WriteOp_Push5_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 5); -} - -inline void WriteOp_Push2_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 2); -} - -inline void WriteOp_Push3_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 3); -} - -inline void WriteOp_Push4_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 4); -} - -inline void WriteOp_Push5_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 5); -} - -inline void WriteOp_Push5(JitWriter *jit) -{ - Macro_PushN(jit, 5); -} - -inline void WriteOp_Push4(JitWriter *jit) -{ - Macro_PushN(jit, 4); -} - -inline void WriteOp_Push3(JitWriter *jit) -{ - Macro_PushN(jit, 3); -} - -inline void WriteOp_Push2(JitWriter *jit) -{ - Macro_PushN(jit, 2); -} - -inline void WriteOp_Zero_Pri(JitWriter *jit) -{ - //xor eax, eax - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Zero_Alt(JitWriter *jit) -{ - //xor edx, edx - IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Add(JitWriter *jit) -{ - //add eax, edx - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Sub(JitWriter *jit) -{ - //sub eax, edx - IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Sub_Alt(JitWriter *jit) -{ - //neg eax - //add eax, edx - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Proc(JitWriter *jit) -{ - CompData *co = (CompData *)jit->data; - - /* Specialized code to align this taking in account the function magic number */ - jitoffs_t cur_offs = jit->get_outputpos(); - jitoffs_t offset = ((cur_offs & 0xFFFFFFF8) + 8) - cur_offs; - if (!((offset + cur_offs) & 8)) - { - offset += 8; - } - if (offset) - { - for (jit_uint32_t i=0; iwrite_ubyte(IA32_INT3); - } - } - - /* Write the info struct about this function */ - jit->write_uint32(JIT_FUNCMAGIC); - jit->write_uint32(co->func_idx); - - /* Now we have to backpatch our reloction offset! */ - { - 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(); - } - - /* Lastly, if we're writing, keep track of the function count */ - if (jit->outbase) - { - co->func_idx++; - } - - //push old frame on stack: - //mov ecx, [esi+frm] - //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_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); - //save frame: - //mov ecx, edi - get new frame - //mov ebx, edi - store frame back - //sub ecx, ebp - relocate local frame - //mov [esi+frm], ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Lidx_B(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - //shl eax, - //add eax, edx - //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); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Idxaddr_B(JitWriter *jit) -{ - //shl eax, - //add eax, edx - cell_t val = jit->read_cell(); - 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); -} - -inline void WriteOp_Shl(JitWriter *jit) -{ - //mov ecx, edx - //shl eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Shr(JitWriter *jit) -{ - //mov ecx, edx - //shr eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Sshr(JitWriter *jit) -{ - //mov ecx, edx - //sar eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Shl_C_Pri(JitWriter *jit) -{ - //shl eax, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG); - } else { - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); - } -} - -inline void WriteOp_Shl_C_Alt(JitWriter *jit) -{ - //shl edx, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG); - } else { - IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_Shr_C_Pri(JitWriter *jit) -{ - //shr eax, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG); - } else { - IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); - } -} - -inline void WriteOp_Shr_C_Alt(JitWriter *jit) -{ - //shr edx, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG); - } else { - IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_SMul(JitWriter *jit) -{ - //mov ecx, edx - //imul edx - //mov edx, ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_Not(JitWriter *jit) -{ - //test eax, eax - //mov eax, 0 - //sete al - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Neg(JitWriter *jit) -{ - //neg eax - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Xor(JitWriter *jit) -{ - //xor eax, edx - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Or(JitWriter *jit) -{ - //or eax, edx - IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_And(JitWriter *jit) -{ - //and eax, edx - IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Invert(JitWriter *jit) -{ - //not eax - IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Add_C(JitWriter *jit) -{ - //add eax, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); - else - IA32_Add_Eax_Imm32(jit, val); -} - -inline void WriteOp_SMul_C(JitWriter *jit) -{ - //imul eax, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); - else - IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val); -} - -inline void WriteOp_Sign_Pri(JitWriter *jit) -{ - //shl eax, 24 - //sar eax, 24 - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); -} - -inline void WriteOp_Sign_Alt(JitWriter *jit) -{ - //shl edx, 24 - //sar edx, 24 - IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); -} - -inline void WriteOp_Eq(JitWriter *jit) -{ - //cmp eax, edx ; PRI == ALT ? - //mov eax, 0 - //sete al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Neq(JitWriter *jit) -{ - //cmp eax, edx ; PRI != ALT ? - //mov eax, 0 - //setne al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE); -} - -inline void WriteOp_Sless(JitWriter *jit) -{ - //cmp eax, edx ; PRI < ALT ? (signed) - //mov eax, 0 - //setl al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L); -} - -inline void WriteOp_Sleq(JitWriter *jit) -{ - //cmp eax, edx ; PRI <= ALT ? (signed) - //mov eax, 0 - //setle al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE); -} - -inline void WriteOp_Sgrtr(JitWriter *jit) -{ - //cmp eax, edx ; PRI > ALT ? (signed) - //mov eax, 0 - //setg al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G); -} - -inline void WriteOp_Sgeq(JitWriter *jit) -{ - //cmp eax, edx ; PRI >= ALT ? (signed) - //mov eax, 0 - //setge al - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE); -} - -inline void WriteOp_Eq_C_Pri(JitWriter *jit) -{ - //cmp eax, ; PRI == value ? - //mov eax, 0 - //sete al - 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); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Eq_C_Alt(JitWriter *jit) -{ - //xor eax, eax - //cmp edx, ; ALT == value ? - //sete al - cell_t val = jit->read_cell(); - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val); - else - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Inc_Pri(JitWriter *jit) -{ - //add eax, 1 - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); -} - -inline void WriteOp_Inc_Alt(JitWriter *jit) -{ - //add edx, 1 - IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); -} - -inline void WriteOp_Inc(JitWriter *jit) -{ - //add [ebp+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); - else - IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); -} - -inline void WriteOp_Inc_S(JitWriter *jit) -{ - //add [ebx+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); - else - IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); -} - -inline void WriteOp_Inc_I(JitWriter *jit) -{ - //add [ebp+eax], 1 - IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); -} - -inline void WriteOp_Dec_Pri(JitWriter *jit) -{ - //sub eax, 1 - IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); -} - -inline void WriteOp_Dec_Alt(JitWriter *jit) -{ - //sub edx, 1 - IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); -} - -inline void WriteOp_Dec(JitWriter *jit) -{ - //sub [ebp+], 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 { - IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); - } -} - -inline void WriteOp_Dec_S(JitWriter *jit) -{ - //sub [ebx+], 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 { - IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); - } -} - -inline void WriteOp_Dec_I(JitWriter *jit) -{ - //sub [ebp+eax], 1 - IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); -} - -inline void WriteOp_Load_Pri(JitWriter *jit) -{ - //mov eax, [ebp+] - 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 { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); - } -} - -inline void WriteOp_Load_Alt(JitWriter *jit) -{ - //mov edx, [ebp+] - 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 { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); - } -} - -inline void WriteOp_Load_S_Pri(JitWriter *jit) -{ - //mov eax, [ebx+] - 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 { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); - } -} - -inline void WriteOp_Load_S_Alt(JitWriter *jit) -{ - //mov edx, [ebx+] - 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 { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); - } -} - -inline void WriteOp_Lref_Pri(JitWriter *jit) -{ - //mov eax, [ebp+] - //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 { - 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); -} - -inline void WriteOp_Lref_Alt(JitWriter *jit) -{ - //mov edx, [ebp+] - //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 { - 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); -} - -inline void WriteOp_Lref_S_Pri(JitWriter *jit) -{ - //mov eax, [ebx+] - //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 { - 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); -} - -inline void WriteOp_Lref_S_Alt(JitWriter *jit) -{ - //mov edx, [ebx+] - //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 { - 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); -} - -inline void WriteOp_Const_Pri(JitWriter *jit) -{ - //mov eax, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val); -} - -inline void WriteOp_Const_Alt(JitWriter *jit) -{ - //mov edx, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val); -} - -inline void WriteOp_Addr_Pri(JitWriter *jit) -{ - //mov eax, [esi+frm] - //add eax, - 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 { - IA32_Add_Eax_Imm32(jit, val); - } -} - -inline void WriteOp_Addr_Alt(JitWriter *jit) -{ - //mov edx, [esi+frm] - //add edx, - 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 { - IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_Stor_Pri(JitWriter *jit) -{ - //mov [ebp+], 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 { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val); - } -} - -inline void WriteOp_Stor_Alt(JitWriter *jit) -{ - //mov [ebp+], 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 { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val); - } -} - -inline void WriteOp_Stor_S_Pri(JitWriter *jit) -{ - //mov [ebx+], 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 { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val); - } -} - -inline void WriteOp_Stor_S_Alt(JitWriter *jit) -{ - //mov [ebx+], 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 { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val); - } -} - -inline void WriteOp_Idxaddr(JitWriter *jit) -{ - //lea eax, [edx+4*eax] - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); -} - -inline void WriteOp_Sref_Pri(JitWriter *jit) -{ - //mov ecx, [ebp+] - //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 { - 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); -} - -inline void WriteOp_Sref_Alt(JitWriter *jit) -{ - //mov ecx, [ebp+] - //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 { - 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); -} - -inline void WriteOp_Sref_S_Pri(JitWriter *jit) -{ - //mov ecx, [ebx+] - //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 { - 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); -} - -inline void WriteOp_Sref_S_Alt(JitWriter *jit) -{ - //mov ecx, [ebx+] - //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 { - 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); -} - -inline void WriteOp_Pop_Pri(JitWriter *jit) -{ - //mov eax, [edi] - //add edi, 4 - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Pop_Alt(JitWriter *jit) -{ - //mov edx, [edi] - //add edi, 4 - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Swap_Pri(JitWriter *jit) -{ - //add [edi], eax - //sub eax, [edi] - //add [edi], eax - //neg eax - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Swap_Alt(JitWriter *jit) -{ - //add [edi], edx - //sub edx, [edi] - //add [edi], edx - //neg edx - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_PushAddr(JitWriter *jit) -{ - //mov ecx, [esi+frm] ;get address (offset from frame) - //sub edi, 4 - //add ecx, - //mov [edi], ecx - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG); - } - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Movs(JitWriter *jit) -{ - //cld - //push esi - //push edi - //lea esi, [ebp+eax] - //lea edi, [ebp+edx] - //if dword: - // mov ecx, dword - // rep movsd - //if byte: - // mov ecx, byte - // rep movsb - //pop edi - //pop esi - cell_t val = jit->read_cell(); - unsigned int dwords = val >> 2; - unsigned int bytes = val & 0x3; - - IA32_Cld(jit); - IA32_Push_Reg(jit, REG_ESI); - IA32_Push_Reg(jit, REG_EDI); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - if (dwords) - { - IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords); - IA32_Rep(jit); - IA32_Movsd(jit); - } - if (bytes) - { - IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes); - IA32_Rep(jit); - IA32_Movsb(jit); - } - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_ESI); -} - -inline void WriteOp_Fill(JitWriter *jit) -{ - //push edi - //lea edi, [ebp+edx] - //mov ecx, >> 2 - //cld - //rep stosd - //pop edi - unsigned int val = jit->read_cell() >> 2; - - IA32_Push_Reg(jit, REG_EDI); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - IA32_Mov_Reg_Imm32(jit, REG_ECX, val); - IA32_Cld(jit); - IA32_Rep(jit); - IA32_Stosd(jit); - IA32_Pop_Reg(jit, REG_EDI); -} - -inline void WriteOp_GenArray(JitWriter *jit, bool autozero) -{ - cell_t val = jit->read_cell(); - if (val == 1) - { - /* flat array. we can generate this without indirection tables. */ - /* Note that we can overwrite ALT because technically STACK should be destroying ALT */ - //mov edx, [esi+info.heap] - //mov ecx, [edi] - //mov [edi], edx ;store base of array into stack - //lea edx, [edx+ecx*4] ;get the final new heap pointer - //mov [esi+info.heap], edx ;store heap pointer back - //add edx, ebp ;relocate - //cmp edx, edi ;compare against stack pointer - //jae :error ;error out if not enough space - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP); - IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); - IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); - - WriteOp_Tracker_Push_Reg(jit, REG_ECX); - - if (autozero) - { - /* Zero out the array - inline a quick fill */ - //push eax ;save pri - //push edi ;save stk - //xor eax, eax ;zero source - //mov edi, [edi] ;get heap ptr out of the stack - //add edi, ebp ;relocate - //cld ;clear direction flag - //rep stosd ;copy (note: ECX is sane from above) - //pop edi ;pop stk - //pop eax ;pop pri - IA32_Push_Reg(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EDI); - IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG); - IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); - IA32_Cld(jit); - IA32_Rep(jit); - IA32_Stosd(jit); - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_EAX); - } - } else { - //mov ecx, num_dims - //mov edx, 0/1 - //call [genarray] - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); - if (autozero) - { - IA32_Mov_Reg_Imm32(jit, REG_EDX, 1); - } else { - IA32_Mov_Reg_Imm32(jit, REG_EDX, 0); - } - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_genarray); - } -} - -inline void WriteOp_Load_Both(JitWriter *jit) -{ - WriteOp_Load_Pri(jit); - WriteOp_Load_Alt(jit); -} - -inline void WriteOp_Load_S_Both(JitWriter *jit) -{ - WriteOp_Load_S_Pri(jit); - WriteOp_Load_S_Alt(jit); -} - -inline void WriteOp_Const(JitWriter *jit) -{ - //mov [ebp+], - cell_t addr = jit->read_cell(); - cell_t val = jit->read_cell(); - if (addr <= SCHAR_MAX && addr >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr); - } -} - -inline void WriteOp_Const_S(JitWriter *jit) -{ - //mov [ebx+], - cell_t offs = jit->read_cell(); - cell_t val = jit->read_cell(); - if (offs <= SCHAR_MAX && offs >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs); - } -} - -inline void WriteOp_Load_I(JitWriter *jit) -{ - //mov eax, [ebp+eax] - 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_Lodb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - - //mov eax, [ebp+eax] - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - - //and eax, - cell_t val = jit->read_cell(); - switch(val) - { - case 1: - { - IA32_And_Eax_Imm32(jit, 0x000000FF); - break; - } - case 2: - { - IA32_And_Eax_Imm32(jit, 0x0000FFFF); - break; - } - } -} - -inline void WriteOp_Stor_I(JitWriter *jit) -{ - //mov [ebp+edx], eax - Write_Check_VerifyAddr(jit, AMX_REG_ALT); - IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); -} - -inline void WriteOp_Strb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_ALT); - //mov [ebp+edx], eax - cell_t val = jit->read_cell(); - switch (val) - { - case 1: - { - IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 2: - { - IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 4: - { - IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - } -} - -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); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Stack(JitWriter *jit) -{ - //add edi, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); - } - - if (val > 0) - { - Write_CheckStack_Min(jit); - } else if (val < 0) { - Write_CheckStack_Low(jit); - } -} - -inline void WriteOp_StackAdjust(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - - assert(val <= 0); - - //lea edi, [ebx-val] - - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Lea_DispRegImm8(jit, AMX_REG_STK, AMX_REG_FRM, val); - } - else - { - IA32_Lea_DispRegImm32(jit, AMX_REG_STK, AMX_REG_FRM, val); - } - - /* We assume the compiler has generated good code -- - * That is, we do not bother validating this amount! - */ -} - -inline void WriteOp_Heap(JitWriter *jit) -{ - //mov edx, [esi+hea] - //add [esi+hea], - 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 { - IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP); - } - - /* 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) -{ - //mov ecx, edx - //mov edx, eax - //sar edx, 31 - //idiv ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_SDiv_Alt(JitWriter *jit) -{ - //mov ecx, eax - //mov eax, edx - //sar edx, 31 - //idiv ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_Retn(JitWriter *jit) -{ - //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_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); - - /* pop params */ - //mov ecx, [edi] - //lea edi, [edi+ecx*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); - - //ret - return (EIP on real stack!) - IA32_Return(jit); -} - -void ProfCallGate_Begin(sp_context_t *ctx, const char *name) -{ - ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionBegin((IPluginContext *)ctx->vm[JITVARS_BASECTX], name); -} - -void ProfCallGate_End(sp_context_t *ctx) -{ - ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionEnd(); -} - -const char *find_func_name(sp_plugin_t *plugin, uint32_t offs) -{ - uint32_t max, iter; - sp_fdbg_symbol_t *sym; - sp_fdbg_arraydim_t *arr; - uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); - - max = plugin->debug.syms_num; - for (iter = 0; iter < max; iter++) - { - sym = (sp_fdbg_symbol_t *)cursor; - - if (sym->ident == SP_SYM_FUNCTION - && sym->codestart <= offs - && sym->codeend > offs) - { - return plugin->debug.stringbase + sym->name; - } - - if (sym->dimcount > 0) - { - cursor += sizeof(sp_fdbg_symbol_t); - arr = (sp_fdbg_arraydim_t *)cursor; - cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; - continue; - } - - cursor += sizeof(sp_fdbg_symbol_t); - } - - return NULL; -} - -inline void WriteOp_Call(JitWriter *jit) -{ - cell_t offs; - jitoffs_t jmp; - CompData *data; - - data = (CompData *)jit->data; - offs = jit->read_cell(); - - if ((data->profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) - { - const char *name; - - /* Find the function name */ - if ((name = find_func_name(data->plugin, offs)) == NULL) - { - name = "unknown"; - } - - //push name - //push [esi+context] - //call ProfCallGate_Begin - //add esp, 8 - IA32_Push_Imm32(jit, (jit_int32_t)(intptr_t)name); - IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_CONTEXT); - jmp = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, jmp, (void *)ProfCallGate_Begin); - IA32_Add_Rm_Imm8(jit, REG_ESP, 8, MOD_REG); - - //call - //push eax - jmp = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false)); - IA32_Push_Reg(jit, REG_EAX); - - //push [esi+context] - //call ProfCallGate_End - //add esp, 4 - //pop eax - IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_CONTEXT); - jmp = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, jmp, (void *)ProfCallGate_End); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - IA32_Pop_Reg(jit, REG_EAX); - } - else - { - jmp = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false)); - } -} - -inline void WriteOp_Bounds(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - - //cmp eax, - //ja :error - 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); - } - IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds); -} - -inline void WriteOp_Halt(JitWriter *jit) -{ - AlignMe(jit); - - //mov ecx, [esi+ret] - //mov [ecx], eax - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL); - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG); - - /* :TODO: - * We don't support sleeping or halting with weird values. - * So we're omitting the mov eax that was here. - */ - jit->read_cell(); - - CompData *data = (CompData *)jit->data; - IA32_Jump_Imm32_Abs(jit, data->jit_return); -} - -inline void WriteOp_Break(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - if (data->debug) - { - //jit->write_ubyte(IA32_INT3); - //mov ecx, - jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0); - jitoffs_t save = jit->get_outputpos(); - jit->set_outputpos(wr); - jit->write_uint32((uint32_t)(wr)); - jit->set_outputpos(save); - wr = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, wr, data->jit_break); - } -} - -inline void WriteOp_Jump(JitWriter *jit) -{ - //jmp - cell_t amx_offs = jit->read_cell(); - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false)); -} - -inline void WriteOp_Jzer(JitWriter *jit) -{ - //test eax, eax - //jz - cell_t target = jit->read_cell(); - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jnz(JitWriter *jit) -{ - //test eax, eax - //jnz - cell_t target = jit->read_cell(); - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jeq(JitWriter *jit) -{ - //cmp eax, edx - //je - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jneq(JitWriter *jit) -{ - //cmp eax, edx - //jne - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jsless(JitWriter *jit) -{ - //cmp eax, edx - //jl - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jsleq(JitWriter *jit) -{ - //cmp eax, edx - //jle - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_JsGrtr(JitWriter *jit) -{ - //cmp eax, edx - //jg - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false)); -} - -inline void WriteOp_JsGeq(JitWriter *jit) -{ - //cmp eax, edx - //jge - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Switch(JitWriter *jit) -{ - cell_t offs = jit->read_cell(); - cell_t *tbl = (cell_t *)((char *)jit->inbase + offs + sizeof(cell_t)); - - struct casetbl - { - cell_t val; - cell_t offs; - }; - - /* Read the number of cases, then advance by one */ - cell_t num_cases = *tbl++; - if (!num_cases) - { - /* Special treatment for 0 cases */ - //jmp - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false)); - } else { - /* Check if the case layout is fully sequential */ - casetbl *iter = (casetbl *)(tbl + 1); - casetbl *cases = iter; - cell_t first = iter[0].val; - cell_t last = first; - bool sequential = true; - for (cell_t i=1; i HIGH) - * This check is valid for both sequential and non-sequential. - */ - cell_t low_bound = cases[0].val; - if (low_bound != 0) - { - /* negate it so we'll get a lower bound of 0 */ - //lea ecx, [eax-] - low_bound = -low_bound; - if (low_bound >= SCHAR_MIN && low_bound <= SCHAR_MAX) - { - IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); - } else { - IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); - } - } else { - //mov ecx, eax - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - } - cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val); - //cmp ecx, - if (high_bound >= SCHAR_MIN && high_bound <= SCHAR_MAX) - { - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound); - } else { - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound); - } - //ja - IA32_Jump_Cond_Imm32_Abs(jit, CC_A, RelocLookup(jit, *tbl, false)); - - /** - * Now we've taken the default case out of the way, it's time to do the - * full check, which is different for sequential vs. non-sequential. - */ - if (sequential) - { - /* we're now theoretically guaranteed to be jumping to a correct offset. - * ECX still has the correctly bound offset in it, luckily! - * thus, we simply need to relocate ECX and store the cases. - */ - //lea ecx, [ecx*4] - //add ecx, - IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0); - 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->get_outputpos(); - jit->set_outputpos(tbl_offs); - jit->write_uint32((jit_uint32_t)(jit->outbase + 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; iwrite_uint32(base + RelocLookup(jit, cases[i].offs, false)); - } - } else { - /* The slow version. Go through each case and generate a check. - * In the future we should replace case tables of more than ~8 cases with a - * hash table lookup. - * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case, - * but only if we're under N cases or so! - * :THOUGHT: Write out a static btree lookup :) - */ - cell_t val; - for (cell_t i=0; i OR cmp al, - if (val >= SCHAR_MIN && val <= SCHAR_MAX) - { - IA32_Cmp_Al_Imm8(jit, val); - } else { - IA32_Cmp_Eax_Imm32(jit, cases[i].val); - } - IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false)); - } - /* After all this, jump to the default case! */ - IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false)); - } - } -} - -inline void WriteOp_Casetbl(JitWriter *jit) -{ - /* do nothing here, switch does all ze work */ - cell_t num_cases = jit->read_cell(); - - /* Two cells per case, one extra case for the default jump */ - num_cases = (num_cases * 2) + 1; - jit->inptr += num_cases; -} - -inline void WriteOp_Sysreq_C(JitWriter *jit) -{ - /* store the number of parameters on the stack, - * and store the native index as well. - */ - cell_t native_index = jit->read_cell(); - - if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num) - { - ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM; - return; - } - - //mov ecx, - IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index); - - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c); -} - -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 native_index = jit->read_cell(); - cell_t num_params = jit->read_cell(); - - if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num) - { - ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM; - return; - } - - //mov eax, - //mov ecx, - IA32_Mov_Reg_Imm32(jit, REG_EAX, num_params); - IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index); - - 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 native_index = jit->read_cell(); - cell_t num_params = jit->read_cell(); - CompData *data = (CompData *)jit->data; - - if ((uint32_t)native_index >= data->plugin->info.natives_num) - { - data->error_set = SP_ERROR_INSTRUCTION_PARAM; - return; - } - - /* 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); - - /* Align the stack to 16 bytes */ - //push ebx - //mov ebx, esp - //and esp, 0xFFFFFF0 - //sub esp, 4 - IA32_Push_Reg(jit, REG_EBX); - IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG); - IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16); - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* push some callback stuff */ - //push edi ; stack - //push ; native index - IA32_Push_Reg(jit, AMX_REG_STK); - if (native_index <= SCHAR_MAX && native_index >= SCHAR_MIN) - { - IA32_Push_Imm8(jit, (jit_int8_t)native_index); - } else { - IA32_Push_Imm32(jit, native_index); - } - - /* Relocate stack, heap, frm information, then store back */ - //mov eax, [esi+context] - //mov ecx, [esi+hea] - //sub edi, ebp - //mov [eax+hp], ecx - //mov ecx, [esi] - //mov [eax+sp], edi - //mov [eax+frm], ecx - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); - IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG); - IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp)); - IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm)); - - /* finally, push the last parameter and make the call */ - //push eax ; context - //call NativeCallback - IA32_Push_Reg(jit, REG_EAX); - jitoffs_t call = IA32_Call_Imm32(jit, 0); - if (!data->debug) - { - if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES) - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Profile); - } - else - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback); - } - } - else - { - if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES) - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug_Profile); - } - else - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug); - } - } - - /* check for errors */ - //mov ecx, [esi+context] - //cmp [ecx+err], 0 - //jnz :error - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error); - - /* restore what we damaged */ - //mov esp, ebx - //pop ebx - //add edi, ebp - //pop edx - IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG); - IA32_Pop_Reg(jit, REG_EBX); - IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG); - IA32_Pop_Reg(jit, AMX_REG_ALT); - - /* 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, - 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); - } -} - -inline void WriteOp_Tracker_Push_C(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - cell_t val = jit->read_cell(); - - /* Save registers that may be damaged by the call */ - //push eax - //push edx - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Push_Reg(jit, AMX_REG_ALT); - - /* Get the context ptr, push it and call the check */ - //mov eax, [esi+context] - //push eax - //call JIT_VerifyOrAllocateTracker - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Push_Reg(jit, REG_EAX); - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker); - - /* Check for errors */ - //cmp eax, 0 - //jnz :error - IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); - - /* Restore */ - //pop eax - IA32_Pop_Reg(jit, REG_EAX); - - /* Push the value into the stack and increment pCur */ - //mov edx, [eax+vm[]] - //mov ecx, [edx+pcur] - //add [edx+pcur], 4 - //mov [ecx], *4 ; we want the count in bytes not in cells - IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); - IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG); - - /* Restore PRI & ALT */ - //pop edx - //pop eax - IA32_Pop_Reg(jit, AMX_REG_ALT); - IA32_Pop_Reg(jit, AMX_REG_PRI); -} - -inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - - /* Save registers that may be damaged by the call */ - //push eax - //push edx - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Push_Reg(jit, AMX_REG_ALT); - - /* Get the context ptr, push it and call the check */ - //mov eax, [esi+context] - //push eax - //call JIT_VerifyLowBoundTracker - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Push_Reg(jit, REG_EAX); - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyLowBoundTracker); - - /* Check for errors */ - //cmp eax, 0 - //jnz :error - IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0); - IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return); - - /* Restore */ - //pop eax - IA32_Pop_Reg(jit, REG_EAX); - - /* Pop the value from the stack and decrease the heap by it*/ - //mov edx, [eax+vm[]] - //sub [edx+pcur], 4 - //mov ecx, [edx+pcur] - //mov ecx, [ecx] - //sub [esi+hea], ecx - IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); - IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG); - IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); - - Write_CheckHeap_Min(jit); - - /* Restore PRI & ALT */ - //pop edx - //pop eax - IA32_Pop_Reg(jit, AMX_REG_ALT); - IA32_Pop_Reg(jit, AMX_REG_PRI); -} - -inline void WriteOp_Stradjust_Pri(JitWriter *jit) -{ - //add eax, 4 - //sar eax, 2 - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 4, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 2, MOD_REG); -} - -inline void WriteOp_FloatAbs(JitWriter *jit) -{ - //mov eax, [edi] - //and eax, 0x7FFFFFFF - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_And_Eax_Imm32(jit, 0x7FFFFFFF); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Float(JitWriter *jit) -{ - //fild [edi] - //push eax - //fstp [esp] - //pop eax - IA32_Fild_Mem32(jit, AMX_REG_STK); - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_FloatAdd(JitWriter *jit) -{ - //push eax - //fld [edi] - //fadd [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fadd_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatSub(JitWriter *jit) -{ - //push eax - //fld [edi] - //fsub [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fsub_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatMul(JitWriter *jit) -{ - //push eax - //fld [edi] - //fmul [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fmul_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatDiv(JitWriter *jit) -{ - //push eax - //fld [edi] - //fdiv [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fdiv_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_RountToNearest(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0x3FF - //fadd st(0), st(0) - //fldcw [esp+4] - - //push eax - //push 0x3F000000 ; 0.5f - //fadd [esp] - //fistp [esp+4] - //pop eax - //pop eax - - //pop ecx - //sar eax, 1 - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x3FF); - IA32_Fadd_FPUreg_ST0(jit, 0); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Push_Imm32(jit, 0x3F000000); - IA32_Fadd_Mem32_ESP(jit); - IA32_Fistp_Mem32_Disp8_Esp(jit, 4); - IA32_Pop_Reg(jit, REG_EAX); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Sar_Rm_1(jit, REG_EAX, MOD_REG); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToFloor(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0x7FF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x7FF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToCeil(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0xBFF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xBFF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToZero(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0xFFF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xFFF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_FloatCompare(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - - //fld [edi] - //fld [edi+4] - //fucomip st(0), st(1) - //mov ecx, - //cmovz eax, [ecx+4] - //cmovb eax, [ecx+8] - //cmova eax, [ecx] - //fstp st(0) - - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fld_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fucomip_ST0_FPUreg(jit, 1); - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, (jit_int32_t)jit->outbase + data->jit_rounding_table); - IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_Z, 4); - IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_B, 8); - IA32_CmovCC_Rm(jit, AMX_REG_TMP, CC_A); - IA32_Fstp_FPUreg(jit, 0); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -/************************************************* - ************************************************* - * JIT PROPER ************************************ - * The rest from now on is the JIT engine * - ************************************************* - *************************************************/ - -cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) -{ - sp_native_t *native; - sp_plugin_t *plugin; - - plugin = (sp_plugin_t *)ctx->vm[JITVARS_PLUGIN]; - - native = &plugin->natives[native_idx]; - - ctx->n_idx = native_idx; - - /* Technically both aren't needed, I guess */ - if (native->status == SP_NATIVE_UNBOUND) - { - ctx->n_err = SP_ERROR_INVALID_NATIVE; - return 0; - } - - return native->pfn(GET_CONTEXT(ctx), params); -} - -cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params) -{ - cell_t val; - sp_native_t *native; - sp_plugin_t *plugin; - - plugin = (sp_plugin_t *)ctx->vm[JITVARS_PLUGIN]; - - native = &plugin->natives[native_idx]; - - ctx->n_idx = native_idx; - - /* Technically both aren't needed, I guess */ - if (native->status == SP_NATIVE_UNBOUND) - { - ctx->n_err = SP_ERROR_INVALID_NATIVE; - return 0; - } - - plugin->profiler->OnNativeBegin(GET_CONTEXT(ctx), native); - val = native->pfn(GET_CONTEXT(ctx), params); - plugin->profiler->OnNativeEnd(); - - return val; -} - -cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params) -{ - cell_t save_sp = ctx->sp; - cell_t save_hp = ctx->hp; - - sp_plugin_t *pl = GETPLUGIN(ctx); - - ctx->n_idx = native_idx; - - if (ctx->hp < (cell_t)pl->data_size) - { - ctx->n_err = SP_ERROR_HEAPMIN; - return 0; - } - - if (ctx->hp + STACK_MARGIN > ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLOW; - return 0; - } - - if ((uint32_t)ctx->sp >= pl->mem_size) - { - ctx->n_err = SP_ERROR_STACKMIN; - return 0; - } - - cell_t result = NativeCallback(ctx, native_idx, params); - - if (ctx->n_err != SP_ERROR_NONE) - { - return result; - } - - if (save_sp != ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLEAK; - return result; - } - else if (save_hp != ctx->hp) - { - ctx->n_err = SP_ERROR_HEAPLEAK; - return result; - } - - return result; -} - -cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params) -{ - cell_t save_sp = ctx->sp; - cell_t save_hp = ctx->hp; - - sp_plugin_t *pl = GETPLUGIN(ctx); - - ctx->n_idx = native_idx; - - if (ctx->hp < (cell_t)pl->data_size) - { - ctx->n_err = SP_ERROR_HEAPMIN; - return 0; - } - - if (ctx->hp + STACK_MARGIN > ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLOW; - return 0; - } - - if ((uint32_t)ctx->sp >= pl->mem_size) - { - ctx->n_err = SP_ERROR_STACKMIN; - return 0; - } - - cell_t result = NativeCallback_Profile(ctx, native_idx, params); - - if (ctx->n_err != SP_ERROR_NONE) - { - return result; - } - - if (save_sp != ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLEAK; - return result; - } - else if (save_hp != ctx->hp) - { - ctx->n_err = SP_ERROR_HEAPLEAK; - return result; - } - - return result; -} - -static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params) -{ - return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native"); -} - -jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) -{ - if (jit->outptr) - { - CompData *data = (CompData *)jit->data; - if (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->get_inputpos(); - } - /* Offset must always be 1)positive and 2)less than or equal to the codesize */ - assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->codesize); - /* Do the lookup in the native dictionary. */ - return *(jitoffs_t *)(data->rebase + pcode_offs); - } - else - { - return 0; - } -} - -void WriteErrorRoutines(CompData *data, JitWriter *jit) -{ - AlignMe(jit); - - data->jit_error_divzero = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO); - - data->jit_error_stacklow = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_STACKLOW); - - data->jit_error_stackmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_STACKMIN); - - data->jit_error_bounds = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS); - - data->jit_error_memaccess = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_MEMACCESS); - - data->jit_error_heaplow = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_HEAPLOW); - - data->jit_error_heapmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_HEAPMIN); - - data->jit_error_array_too_big = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG); - - data->jit_extern_error = jit->get_outputpos(); - Write_GetError(jit); -} - -bool JITX86::Compile(ICompilation *co, BaseRuntime *prt, int *err) -{ - CompData *data = (CompData *)co; - sp_plugin_t *plugin = data->plugin; - - if (data->plugin == NULL) - { - if (data->debug && !(prt->m_pPlugin->flags & SP_FLAG_DEBUG)) - { - if (err != NULL) - { - *err = SP_ERROR_NOTDEBUGGING; - } - co->Abort(); - return false; - } - - data->SetRuntime(prt); - plugin = data->plugin; - } - - /* The first phase is to browse */ - uint8_t *code = plugin->pcode; - uint8_t *end_cip = plugin->pcode + plugin->pcode_size; - OPCODE op; - - /********************************************* - * FIRST PASS (medium load): writer.outbase is NULL, getting size only - * SECOND PASS (heavy load!!): writer.outbase is valid and output is written - *********************************************/ - - JitWriter writer; - JitWriter *jit = &writer; - cell_t *endptr = (cell_t *)(end_cip); - uint32_t codemem = 0; - - /* Initial code is written "blank," - * 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; - /* Allocate relocation. One extra cell for final CIP. */ - data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size + sizeof(cell_t)); - - /* We will jump back here for second pass */ -jit_rewind: - /* Initialize pass vars */ - writer.inptr = writer.inbase; - data->jit_verify_addr_eax = 0; - data->jit_verify_addr_edx = 0; - - /* Write the prologue of the JIT */ - data->jit_return = Write_Execute_Function(jit); - - /* Write the SYSREQ.N opcode if we need to */ - if (!(data->inline_level & JIT_INLINE_NATIVES)) - { - AlignMe(jit); - data->jit_sysreq_n = jit->get_outputpos(); - WriteOp_Sysreq_N_Function(jit); - } - - /* Write the debug section if we need it */ - if (data->debug == true) - { - AlignMe(jit); - data->jit_break = jit->get_outputpos(); - Write_BreakDebug(jit); - } - - /* Plugins compiled with -O0 will need this! */ - AlignMe(jit); - data->jit_sysreq_c = jit->get_outputpos(); - WriteOp_Sysreq_C_Function(jit); - - AlignMe(jit); - data->jit_genarray = jit->get_outputpos(); - WriteIntrinsic_GenArray(jit); - - /* Write error checking routines that are called to */ - if (!(data->inline_level & JIT_INLINE_ERRORCHECKS)) - { - AlignMe(jit); - data->jit_verify_addr_eax = jit->get_outputpos(); - Write_Check_VerifyAddr(jit, REG_EAX); - - AlignMe(jit); - data->jit_verify_addr_edx = jit->get_outputpos(); - Write_Check_VerifyAddr(jit, REG_EDX); - } - - /* Write the rounding table for the float compare opcode */ - data->jit_rounding_table = jit->get_outputpos(); - Write_RoundingTable(jit); - - /* Actual code generation! */ - if (writer.outbase == NULL) - { - /* First Pass - find codesize and resolve relocation */ - jitoffs_t pcode_offs; - jitoffs_t native_offs; - - 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->get_outputpos(); - *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; - - /* Now read the opcode and continue. */ - op = (OPCODE)writer.read_cell(); - - /* Patch the floating point natives with our opcodes */ - if (op == OP_SYSREQ_N) - { - cell_t idx = writer.read_cell(); - if (data->jit_float_table[idx].found) - { - writer.inptr -= 2; - *(writer.inptr++) = data->jit_float_table[idx].index; - *(writer.inptr++) = OP_NOP; - *(writer.inptr++) = OP_NOP; - op = (OPCODE)data->jit_float_table[idx].index; - } - else - { - writer.inptr--; - } - } - switch (op) - { - #include "opcode_switch.inc" - } - /* Check for errors. This should only happen in the first pass. */ - if (data->error_set != SP_ERROR_NONE) - { - *err = data->error_set; - co->Abort(); - return false; - } - } - /* Write these last because error jumps should be unpredicted, and thus forward */ - WriteErrorRoutines(data, jit); - - /* Write the final CIP to the last position in the reloc array */ - pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); - native_offs = jit->get_outputpos(); - *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; - - /* the total codesize is now known! */ - codemem = writer.get_outputpos(); - writer.outbase = (jitcode_t)engine->AllocatePageMemory(codemem); - engine->SetReadWrite(writer.outbase); - writer.outptr = writer.outbase; - /* go back for third pass */ - goto jit_rewind; - } - else - { - /******* - * THIRD PASS - write opcode info - *******/ - for (; writer.inptr < endptr;) - { - op = (OPCODE)writer.read_cell(); - switch (op) - { - #include "opcode_switch.inc" - } - } - /* Write these last because error jumps should be unpredicted, and thus forward */ - WriteErrorRoutines(data, jit); - - engine->SetReadExecute(writer.outbase); - } - - /************* - * FOURTH PASS - Context Setup - *************/ - - /* setup basics */ - sp_context_t *ctx = data->runtime->GetBaseContext()->GetCtx(); - - /* Clear out any old cruft */ - if (plugin->codebase != NULL) - { - FreePluginVars(data->runtime->m_pPlugin); - FreeContextVars(ctx); - } - - plugin->codebase = writer.outbase; - plugin->jit_codesize = codemem; - plugin->jit_memsize = 0; - - /* setup memory */ - - ctx->hp = plugin->data_size; - ctx->sp = plugin->mem_size - sizeof(cell_t); - ctx->frm = ctx->sp; - ctx->n_err = SP_ERROR_NONE; - ctx->n_idx = SP_ERROR_NONE; - plugin->prof_flags = data->profile; - plugin->flags = data->debug ? SPFLAG_PLUGIN_DEBUG : 0; - - const char *strbase = plugin->info.stringbase; - uint32_t max, iter; - - /* relocate public info */ - if ((max = plugin->info.publics_num)) - { - plugin->publics = new sp_public_t[max]; - plugin->jit_memsize += sizeof(sp_public_t) * max; - for (iter=0; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; - plugin->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false); - /* Encode the ID as a straight code offset */ - plugin->publics[iter].funcid = (plugin->publics[iter].code_offs << 1); - } - } - - /* relocate pubvar info */ - if ((max = plugin->info.pubvars_num)) - { - uint8_t *dat = plugin->memory; - plugin->pubvars = new sp_pubvar_t[max]; - plugin->jit_memsize += sizeof(sp_pubvar_t) * max; - for (iter=0; iterpubvars[iter].name = strbase + plugin->info.pubvars[iter].name; - plugin->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); - } - } - - /* relocate native info */ - if ((max = plugin->info.natives_num)) - { - plugin->natives = new sp_native_t[max]; - plugin->jit_memsize += sizeof(sp_native_t) * max; - for (iter=0; iternatives[iter].name = strbase + plugin->info.natives[iter].name; - plugin->natives[iter].pfn = &InvalidNative; - plugin->natives[iter].status = SP_NATIVE_UNBOUND; - plugin->natives[iter].flags = 0; - plugin->natives[iter].user = NULL; - } - } - - /** - * If we're debugging, make sure we copy the necessary info. - */ - if (data->debug) - { - strbase = plugin->debug.stringbase; - - /* relocate files */ - max = plugin->debug.files_num; - plugin->files = new sp_debug_file_t[max]; - plugin->jit_memsize += sizeof(sp_debug_file_t) * max; - for (iter=0; iterfiles[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false); - plugin->files[iter].name = strbase + plugin->debug.files[iter].name; - } - - /* relocate lines */ - max = plugin->debug.lines_num; - plugin->lines = new sp_debug_line_t[max]; - plugin->jit_memsize += sizeof(sp_debug_line_t) * max; - for (iter=0; iterlines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false); - plugin->lines[iter].line = plugin->debug.lines[iter].line; - } - - /* relocate arrays */ - sp_fdbg_symbol_t *sym; - sp_fdbg_arraydim_t *arr; - uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); - - max = plugin->debug.syms_num; - plugin->symbols = new sp_debug_symbol_t[max]; - plugin->jit_memsize += sizeof(sp_debug_symbol_t) * max; - for (iter=0; itercodestart > data->codesize) - { - plugin->symbols[iter].codestart = 0; - } else { - plugin->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); - } - if (sym->codeend > data->codesize) - { - plugin->symbols[iter].codeend = data->codesize; - } else { - plugin->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false); - } - plugin->symbols[iter].name = strbase + sym->name; - plugin->symbols[iter].sym = sym; - - if (sym->dimcount > 0) - { - cursor += sizeof(sp_fdbg_symbol_t); - arr = (sp_fdbg_arraydim_t *)cursor; - plugin->symbols[iter].dims = arr; - cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; - continue; - } - - plugin->symbols[iter].dims = NULL; - cursor += sizeof(sp_fdbg_symbol_t); - } - } - - tracker_t *trk = new tracker_t; - ctx->vm[JITVARS_TRACKER] = trk; - ctx->vm[JITVARS_BASECTX] = data->runtime->GetDefaultContext(); - ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler(); - ctx->vm[JITVARS_PLUGIN] = data->runtime->m_pPlugin; - trk->pBase = (ucell_t *)malloc(1024); - trk->pCur = trk->pBase; - trk->size = 1024 / sizeof(cell_t); - - plugin->jit_memsize += trk->size; - - /* clean up relocation+compilation memory */ - co->Abort(); - - *err = SP_ERROR_NONE; - - return true; -} - -SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) -{ - JitWriter jw; - JitWriter *jit = &jw; - - jw.outbase = NULL; - jw.outptr = NULL; - jw.data = NULL; - - /* First pass, calculate size */ -rewind: - /* Align the stack to 16 bytes */ - //push ebx - //push edi - //push esi - //mov edi, [esp+16] ;store ctx - //mov esi, [esp+20] ;store params - //mov ebx, esp - //and esp, 0xFFFFFF0 - //sub esp, 4 - IA32_Push_Reg(jit, REG_EBX); - IA32_Push_Reg(jit, REG_EDI); - IA32_Push_Reg(jit, REG_ESI); - IA32_Mov_Reg_Esp_Disp8(jit, REG_EDI, 16); - IA32_Mov_Reg_Esp_Disp8(jit, REG_ESI, 20); - IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG); - IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16); - IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - //push pData ;push pData - //push esi ;push params - //push edi ;push ctx - //call [callback] ;invoke the meta-callback - //mov esp, ebx ;restore the stack - //pop esi ;restore esi - //pop edi ;restore edi - //pop ebx ;restore ebx - //ret ;return - IA32_Push_Imm32(jit, (jit_int32_t)pData); - IA32_Push_Reg(jit, REG_ESI); - IA32_Push_Reg(jit, REG_EDI); - uint32_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)callback); - IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG); - IA32_Pop_Reg(jit, REG_ESI); - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_EBX); - IA32_Return(jit); - - if (jw.outbase == NULL) - { - /* Second pass: Actually write */ - jw.outbase = (jitcode_t)engine->AllocatePageMemory(jw.get_outputpos()); - if (!jw.outbase) - { - return NULL; - } - engine->SetReadWrite(jw.outbase); - jw.outptr = jw.outbase; - - goto rewind; - } - - engine->SetReadExecute(jw.outbase); - - return (SPVM_NATIVE_FUNC)jw.outbase; -} - -void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) -{ - engine->FreePageMemory((void *)func); -} - -int JITX86::ContextExecute(sp_plugin_t *pl, 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)pl->codebase; - return fn(ctx, code_idx, result); -} - -ICompilation *JITX86::StartCompilation() -{ - CompData *data = new CompData; - - data->jit_float_table = NULL; - - return data; -} - -void CompData::SetRuntime(BaseRuntime *runtime) -{ - plugin = runtime->m_pPlugin; - - uint32_t max_natives = plugin->info.natives_num; - const char *strbase = plugin->info.stringbase; - - this->runtime = runtime; - - inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES; - error_set = SP_ERROR_NONE; - - jit_float_table = new floattbl_t[max_natives]; - for (uint32_t i=0; iinfo.natives[i].name; - if (!strcmp(name, "FloatAbs")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FABS; - } else if (!strcmp(name, "FloatAdd")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATADD; - } else if (!strcmp(name, "FloatSub")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATSUB; - } else if (!strcmp(name, "FloatMul")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATMUL; - } else if (!strcmp(name, "FloatDiv")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATDIV; - } else if (!strcmp(name, "float")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOAT; - } else if (!strcmp(name, "FloatCompare")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATCMP; - } else if (!strcmp(name, "RoundToZero")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_ZERO; - } else if (!strcmp(name, "RoundToCeil")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_CEIL; - } else if (!strcmp(name, "RoundToFloor")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_FLOOR; - } else if (!strcmp(name, "RoundToNearest")) { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_NEAREST; - } - } -} - -ICompilation *JITX86::StartCompilation(BaseRuntime *runtime) -{ - CompData *data = new CompData; - - data->SetRuntime(runtime); - - return data; -} - -void CompData::Abort() -{ - if (rebase) - { - engine->BaseFree(rebase); - } - delete [] jit_float_table; - delete this; -} - -void JITX86::FreeContextVars(sp_context_t *ctx) -{ - free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); - delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; -} - -void JITX86::FreePluginVars(sp_plugin_t *pl) -{ - delete [] pl->files; - delete [] pl->lines; - delete [] pl->natives; - delete [] pl->publics; - delete [] pl->pubvars; - delete [] pl->symbols; - - if (pl->codebase != NULL) - { - g_engine1.FreePageMemory(pl->codebase); - pl->codebase = NULL; - } - - pl->files = NULL; - pl->lines = NULL; - pl->natives = NULL; - pl->publics = NULL; - pl->pubvars = NULL; - pl->symbols = NULL; -} - -bool CompData::SetOption(const char *key, const char *val) -{ - if (strcmp(key, SP_JITCONF_DEBUG) == 0) - { - if ((atoi(val) == 1) || !strcmp(val, "yes")) - { - debug = true; - } else { - debug = false; - } - if (debug && plugin && !(plugin->flags & SP_FLAG_DEBUG)) - { - debug = false; - return false; - } - return true; - } - else if (strcmp(key, SP_JITCONF_PROFILE) == 0) - { - profile = atoi(val); - - /** Callbacks must be profiled to profile functions! */ - if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) - { - profile |= SP_PROF_CALLBACKS; - } - - return true; - } - - return false; -} -