All plugin and include file headers also have been changed to say about GPL3 instead of GPL2. (This day shall henceforth be known as the Eighty Column Massacre of '07) --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401336
		
			
				
	
	
		
			2822 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2822 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * vim: set ts=4 :
 | |
|  * =============================================================================
 | |
|  * SourcePawn JIT
 | |
|  * Copyright (C)2004-2007 AlliedModders LLC.  All rights reserved.
 | |
|  * =============================================================================
 | |
|  *
 | |
|  * This file is not open source and may not be copied without explicit wriiten
 | |
|  * permission of AlliedModders LLC.  This file may not be redistributed in whole
 | |
|  * or significant part.
 | |
|  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
 | |
|  *
 | |
|  * Version: $Id$
 | |
|  */
 | |
| 
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <assert.h>
 | |
| #include "jit_x86.h"
 | |
| #include "opcode_helpers.h"
 | |
| #include <x86_macros.h>
 | |
| #include "jit_version.h"
 | |
| 
 | |
| #if defined USE_UNGEN_OPCODES
 | |
| #include "ungen_opcodes.h"
 | |
| #endif
 | |
| 
 | |
| 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+<val>]
 | |
| 	//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], <val>
 | |
| 	//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+<val>], 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+<val>], 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+<val>]
 | |
| 	//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; i<offset; i++)
 | |
| 		{
 | |
| 			jit->write_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, <val>
 | |
| 	//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, <val>
 | |
| 	//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, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>   ; 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, <val>   ; 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+<val>], 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+<val>], 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+<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 {
 | |
| 		IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		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+<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 {
 | |
| 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| inline void WriteOp_Lref_Pri(JitWriter *jit)
 | |
| {
 | |
| 	//mov eax, [ebp+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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, <val>
 | |
| 	cell_t val = jit->read_cell();
 | |
| 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val);
 | |
| }
 | |
| 
 | |
| inline void WriteOp_Const_Alt(JitWriter *jit)
 | |
| {
 | |
| 	//mov edx, <val>
 | |
| 	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, <val>
 | |
| 	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, <val>
 | |
| 	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+<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 {
 | |
| 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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 {
 | |
| 		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+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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+<val>]
 | |
| 	//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, <val>
 | |
| 	//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, <val> >> 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+<addr>], <val>
 | |
| 	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+<offs>], <val>
 | |
| 	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, <bitmask>
 | |
| 	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, <val>
 | |
| 	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_Heap(JitWriter *jit)
 | |
| {
 | |
| 	//mov edx, [esi+hea]
 | |
| 	//add [esi+hea], <val>
 | |
| 	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);
 | |
| }
 | |
| 
 | |
| inline void WriteOp_Call(JitWriter *jit)
 | |
| {
 | |
| 	cell_t offs = jit->read_cell();
 | |
| 
 | |
| 	jitoffs_t 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, <val>
 | |
| 	//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 <val> 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, <cip>
 | |
| 		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 <offs>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <target>
 | |
| 	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 <default>
 | |
| 		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<num_cases; i++)
 | |
| 		{
 | |
| 			if (iter[i].val != ++last)
 | |
| 			{
 | |
| 				sequential = false;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		/* Time to generate. 
 | |
| 		 * First check whether the bounds are correct: if (a < LOW || a > 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-<LOWER_BOUND>]
 | |
| 			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, <UPPER BOUND BOUND>
 | |
| 		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 <default case>
 | |
| 		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, <case table start>
 | |
| 			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; i<num_cases; i++)
 | |
| 			{
 | |
| 				jit->write_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<num_cases; i++)
 | |
| 			{
 | |
| 				val = cases[i].val;
 | |
| 				//cmp eax, <val> OR cmp al, <val>
 | |
| 				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, <native_index>
 | |
| 	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, <num_params>
 | |
| 	//mov ecx, <native_index>
 | |
| 	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>	; 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)
 | |
| 	{
 | |
| 		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
 | |
| 	} 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, <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);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 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], <val>*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, <round_table>
 | |
| 	//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 = &ctx->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(ctx->context, params);
 | |
| }
 | |
| 
 | |
| static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
 | |
| {
 | |
| 	sp_context_t *ctx = pCtx->GetContext();
 | |
| 	ctx->n_err = SP_ERROR_INVALID_NATIVE;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 
 | |
| 	ctx->n_idx = native_idx;
 | |
| 
 | |
| 	if (ctx->hp < ctx->heap_base)
 | |
| 	{
 | |
| 		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 >= ctx->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;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
 | |
| {
 | |
| 	CompData *data = (CompData *)co;
 | |
| 	sp_plugin_t *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;
 | |
| 				AbortCompilation(co);
 | |
| 				return NULL;
 | |
| 			}
 | |
| 		}
 | |
| 		/* 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->ExecAlloc(codemem);
 | |
| 		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);
 | |
| 	}
 | |
| 
 | |
| 	/*************
 | |
| 	 * FOURTH PASS - Context Setup
 | |
| 	 *************/
 | |
| 
 | |
| 	sp_context_t *ctx = new sp_context_t;
 | |
| 	memset(ctx, 0, sizeof(sp_context_t));
 | |
| 
 | |
| 	/* setup  basics */
 | |
| 	ctx->codebase = writer.outbase;
 | |
| 	ctx->plugin = plugin;
 | |
| 	ctx->vmbase = this;
 | |
| 	ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0);
 | |
| 
 | |
| 	/* setup memory */
 | |
| 	ctx->memory = new uint8_t[plugin->memory];
 | |
| 	memcpy(ctx->memory, plugin->data, plugin->data_size);
 | |
| 	ctx->mem_size = plugin->memory;
 | |
| 	ctx->heap_base = plugin->data_size;
 | |
| 	ctx->hp = ctx->heap_base;
 | |
| 	ctx->sp = ctx->mem_size - sizeof(cell_t);
 | |
| 
 | |
| 	const char *strbase = plugin->info.stringbase;
 | |
| 	uint32_t max, iter;
 | |
| 
 | |
| 	/* relocate public info */
 | |
| 	if ((max = plugin->info.publics_num))
 | |
| 	{
 | |
| 		ctx->publics = new sp_public_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			ctx->publics[iter].name = strbase + plugin->info.publics[iter].name;
 | |
| 			ctx->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false);
 | |
| 			/* Encode the ID as a straight code offset */
 | |
| 			ctx->publics[iter].funcid = (ctx->publics[iter].code_offs << 1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* relocate pubvar info */
 | |
| 	if ((max = plugin->info.pubvars_num))
 | |
| 	{
 | |
| 		uint8_t *dat = ctx->memory;
 | |
| 		ctx->pubvars = new sp_pubvar_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			ctx->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name;
 | |
| 			ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* relocate native info */
 | |
| 	if ((max = plugin->info.natives_num))
 | |
| 	{
 | |
| 		ctx->natives = new sp_native_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			ctx->natives[iter].name = strbase + plugin->info.natives[iter].name;
 | |
| 			ctx->natives[iter].pfn = &InvalidNative;
 | |
| 			ctx->natives[iter].status = SP_NATIVE_UNBOUND;
 | |
| 			ctx->natives[iter].flags = 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * 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;
 | |
| 		ctx->files = new sp_debug_file_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			ctx->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false);
 | |
| 			ctx->files[iter].name = strbase + plugin->debug.files[iter].name;
 | |
| 		}
 | |
| 
 | |
| 		/* relocate lines */
 | |
| 		max = plugin->debug.lines_num;
 | |
| 		ctx->lines = new sp_debug_line_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			ctx->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false);
 | |
| 			ctx->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;
 | |
| 		ctx->symbols = new sp_debug_symbol_t[max];
 | |
| 		for (iter=0; iter<max; iter++)
 | |
| 		{
 | |
| 			sym = (sp_fdbg_symbol_t *)cursor;
 | |
| 
 | |
| 			/**
 | |
| 			 * @brief There is an "issue" where the compiler will give totally bogus code 
 | |
| 			 * address because codegeneration is still being calculated.  A simple fix for 
 | |
| 			 * this is to coerce the codestart value to 0 when it's invalid.
 | |
| 			 */
 | |
| 			if (sym->codestart > data->codesize)
 | |
| 			{
 | |
| 				ctx->symbols[iter].codestart = 0;
 | |
| 			} else {
 | |
| 				ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false);
 | |
| 			}
 | |
| 			if (sym->codeend > data->codesize)
 | |
| 			{
 | |
| 				ctx->symbols[iter].codeend = data->codesize;
 | |
| 			} else {
 | |
| 				ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false);
 | |
| 			}
 | |
| 			ctx->symbols[iter].name = strbase + sym->name;
 | |
| 			ctx->symbols[iter].sym = sym;
 | |
| 
 | |
| 			if (sym->dimcount > 0)
 | |
| 			{
 | |
| 				cursor += sizeof(sp_fdbg_symbol_t);
 | |
| 				arr = (sp_fdbg_arraydim_t *)cursor;
 | |
| 				ctx->symbols[iter].dims = arr;
 | |
| 				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			ctx->symbols[iter].dims = NULL;
 | |
| 			cursor += sizeof(sp_fdbg_symbol_t);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tracker_t *trk = new tracker_t;
 | |
| 	ctx->vm[JITVARS_TRACKER] = trk;
 | |
| 	trk->pBase = (ucell_t *)malloc(1024);
 | |
| 	trk->pCur = trk->pBase;
 | |
| 	trk->size = 1024 / sizeof(cell_t);
 | |
| 
 | |
| 	functracker_t *fnc = new functracker_t;
 | |
| 	ctx->vm[JITVARS_FUNCINFO] = fnc;
 | |
| 	ctx->vm[JITVARS_REBASE] = data->rebase;
 | |
| 	fnc->code_size = codemem;
 | |
| 	fnc->num_functions = data->func_idx;
 | |
| 
 | |
| 	/* clean up relocation+compilation memory */
 | |
| 	data->rebase = NULL;
 | |
| 	AbortCompilation(co);
 | |
| 
 | |
| 	*err = SP_ERROR_NONE;
 | |
| 
 | |
| 	return ctx;
 | |
| }
 | |
| 
 | |
| 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->ExecAlloc(jw.get_outputpos());
 | |
| 		if (!jw.outbase)
 | |
| 		{
 | |
| 			return NULL;
 | |
| 		}
 | |
| 		jw.outptr = jw.outbase;
 | |
| 	
 | |
| 		goto rewind;
 | |
| 	}
 | |
| 	
 | |
| 	return (SPVM_NATIVE_FUNC)jw.outbase;
 | |
| }
 | |
| 
 | |
| void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
 | |
| {
 | |
| 	engine->ExecFree((void *)func);
 | |
| }
 | |
| 
 | |
| const char *JITX86::GetVMName()
 | |
| {
 | |
| 	return "JIT (x86)";
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 	return fn(ctx, code_idx, result);
 | |
| }
 | |
| 
 | |
| void JITX86::FreeContext(sp_context_t *ctx)
 | |
| {
 | |
| 	engine->ExecFree(ctx->codebase);
 | |
| 	delete [] ctx->memory;
 | |
| 	delete [] ctx->files;
 | |
| 	delete [] ctx->lines;
 | |
| 	delete [] ctx->natives;
 | |
| 	delete [] ctx->publics;
 | |
| 	delete [] ctx->pubvars;
 | |
| 	delete [] ctx->symbols;
 | |
| 	engine->BaseFree(ctx->vm[JITVARS_REBASE]);
 | |
| 	free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
 | |
| 	delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
 | |
| 	delete (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
 | |
| 	delete ctx;
 | |
| }
 | |
| 
 | |
| ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin)
 | |
| {
 | |
| 	CompData *data = new CompData;
 | |
| 	uint32_t max_natives = plugin->info.natives_num;
 | |
| 	const char *strbase = plugin->info.stringbase;
 | |
| 
 | |
| 	data->plugin = plugin;
 | |
| 	data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
 | |
| 	data->error_set = SP_ERROR_NONE;
 | |
| 
 | |
| 	data->jit_float_table = new floattbl_t[max_natives];
 | |
| 	for (uint32_t i=0; i<max_natives; i++)
 | |
| 	{
 | |
| 		const char *name = strbase + plugin->info.natives[i].name;
 | |
| 		if (!strcmp(name, "FloatAbs"))
 | |
| 		{
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FABS;
 | |
| 		} else if (!strcmp(name, "FloatAdd")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOATADD;
 | |
| 		} else if (!strcmp(name, "FloatSub")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOATSUB;
 | |
| 		} else if (!strcmp(name, "FloatMul")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOATMUL;
 | |
| 		} else if (!strcmp(name, "FloatDiv")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOATDIV;
 | |
| 		} else if (!strcmp(name, "float")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOAT;
 | |
| 		} else if (!strcmp(name, "FloatCompare")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_FLOATCMP;
 | |
| 		} else if (!strcmp(name, "RoundToZero")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_RND_TO_ZERO;
 | |
| 		} else if (!strcmp(name, "RoundToCeil")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_RND_TO_CEIL;
 | |
| 		} else if (!strcmp(name, "RoundToFloor")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_RND_TO_FLOOR;
 | |
| 		} else if (!strcmp(name, "RoundToNearest")) {
 | |
| 			data->jit_float_table[i].found = true;
 | |
| 			data->jit_float_table[i].index = OP_RND_TO_NEAREST;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return data;
 | |
| }
 | |
| 
 | |
| void JITX86::AbortCompilation(ICompilation *co)
 | |
| {
 | |
| 	if (((CompData *)co)->rebase)
 | |
| 	{
 | |
| 		engine->BaseFree(((CompData *)co)->rebase);
 | |
| 	}
 | |
| 	delete [] ((CompData *)co)->jit_float_table;
 | |
| 	delete (CompData *)co;
 | |
| }
 | |
| 
 | |
| bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char *val)
 | |
| {
 | |
| 	CompData *data = (CompData *)co;
 | |
| 
 | |
| 	if (strcmp(key, "debug") == 0)
 | |
| 	{
 | |
| 		if ((atoi(val) == 1) || !strcmp(val, "yes"))
 | |
| 		{
 | |
| 			data->debug = true;
 | |
| 		} else {
 | |
| 			data->debug = false;
 | |
| 		}
 | |
| 		if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG))
 | |
| 		{
 | |
| 			data->debug = false;
 | |
| 			return false;
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| unsigned int JITX86::GetAPIVersion()
 | |
| {
 | |
| 	return SOURCEPAWN_VM_API_VERSION;
 | |
| }
 | |
| 
 | |
| bool JITX86::FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
 | |
| {
 | |
| 	uint8_t *rebase = (uint8_t *)ctx->vm[JITVARS_REBASE];
 | |
| 
 | |
| 	/* Is this within the pcode bounds? */
 | |
| 	if (code_addr >= ctx->plugin->pcode_size - sizeof(uint32_t))
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/* Relocate this */
 | |
| 	code_addr = *(jitoffs_t *)(rebase + code_addr);
 | |
| 
 | |
| 	/* Check if this is in the relocation bounds */
 | |
| 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
 | |
| 	if (code_addr >= fnc->code_size)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/* Get the function info and sanity check */
 | |
| 	funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
 | |
| 	if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (result)
 | |
| 	{
 | |
| 		*result = f->index;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
 | |
| {
 | |
| 	/* Check if this is in the relocation bounds */
 | |
| 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
 | |
| 	if (code_addr >= fnc->code_size)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/* Get the function info and sanity check */
 | |
| 	funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
 | |
| 	if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (result)
 | |
| 	{
 | |
| 		*result = f->index;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| unsigned int JITX86::FunctionCount(const sp_context_t *ctx)
 | |
| {
 | |
| 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
 | |
| 
 | |
| 	return fnc->num_functions;
 | |
| }
 | |
| 
 | |
| const char *JITX86::GetVersionString()
 | |
| {
 | |
| 	return SVN_FULL_VERSION;
 | |
| }
 | |
| 
 | |
| const char *JITX86::GetCPUOptimizations()
 | |
| {
 | |
| 	return "Generic i686";
 | |
| }
 |