From 824beee935112abb731738064e58bdbf747e84fb Mon Sep 17 00:00:00 2001
From: David Anderson <dvander@alliedmods.net>
Date: Wed, 20 Sep 2006 07:07:49 +0000
Subject: [PATCH] Wrote the JIT execution function Solidified some more code

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%4079
---
 sourcepawn/vm/jit/x86/jit_x86.cpp        |  33 +++---
 sourcepawn/vm/jit/x86/jit_x86.h          |   5 +-
 sourcepawn/vm/jit/x86/opcode_helpers.cpp | 128 +++++++++++++++++++++--
 sourcepawn/vm/jit/x86/opcode_helpers.h   |  13 +++
 sourcepawn/vm/jit/x86/x86_macros.h       |  25 +++++
 sourcepawn/vm/msvc8/vm.vcproj            |   8 +-
 sourcepawn/vm/sp_vm_basecontext.cpp      |  13 ++-
 7 files changed, 193 insertions(+), 32 deletions(-)

diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp
index 693890d5..ca58068b 100644
--- a/sourcepawn/vm/jit/x86/jit_x86.cpp
+++ b/sourcepawn/vm/jit/x86/jit_x86.cpp
@@ -830,7 +830,6 @@ inline void WriteOp_Pop_Pri(JitWriter *jit)
 	//add ebp, 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)
@@ -1049,16 +1048,6 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err)
 		} else if (op_c == -1) {
 			switch (op)
 			{
-			case OP_SYSREQ_C:
-			case OP_SYSREQ_PRI:
-			case OP_SYSREQ_N:
-				{
-					if (!data->always_inline)
-					{
-						reloc_count++;
-					}
-					break;
-				}
 			case OP_CASETBL:
 				{
 					ucell_t num = *(ucell_t *)cip;
@@ -1083,14 +1072,30 @@ IPluginContext *JITX86::CompileToContext(ICompilation *co, int *err)
 	 *********************************************/
 
 	JitWriter writer;
+	JitWriter *jit = &writer;
+	cell_t *endptr = (cell_t *)(end_cip);
+	jitoffs_t jit_return;
 
+	/* Initial code is written "blank,"
+	 * so we can check the exact memory usage.
+	 */
 	writer.inptr = (cell_t *)code;
 	writer.outptr = NULL;
 	writer.outbase = NULL;
 
-//redo_pass:
-	cell_t *endptr = (cell_t *)(end_cip);
-	JitWriter *jit = &writer;
+	/* Get inlining level */
+	int inline_level = data->inline_level;
+	bool never_inline = false;
+
+	if (inline_level == 0)
+	{
+		never_inline = true;
+	}
+
+//:TODO: Jump back here once finished!
+	/* Start writing the actual code */
+	jit_return = Write_Execute_Function(jit, never_inline);
+
 	for (; writer.inptr <= endptr;)
 	{
 		op = (OPCODE)writer.read_cell();
diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h
index 7fa56ce2..b3ba2e8d 100644
--- a/sourcepawn/vm/jit/x86/jit_x86.h
+++ b/sourcepawn/vm/jit/x86/jit_x86.h
@@ -9,12 +9,12 @@ using namespace SourcePawn;
 class CompData : public ICompilation
 {
 public:
-	CompData() : plugin(NULL), debug(false), always_inline(true)
+	CompData() : plugin(NULL), debug(false), inline_level(2)
 	{
 	};
 public:
 	sp_plugin_t *plugin;
-	bool always_inline;
+	int inline_level;
 	bool debug;
 };
 
@@ -43,5 +43,6 @@ public:
 #define AMX_INFO_FRM		AMX_REG_INFO
 #define AMX_INFO_HEAP		4
 #define AMX_INFO_RETVAL		8
+#define AMX_INFO_CONTEXT	12
 
 #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp
index 012f3a05..43e39e77 100644
--- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp
+++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp
@@ -6,26 +6,129 @@
 
 int OpAdvTable[OP_NUM_OPCODES];
 
-void Write_Prologue(JitWriter *jit)
+jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline)
 {
 	/** 
 	 * The state expected by our plugin is:
-	 * #define AMX_REG_PRI		REG_EAX
-	   #define AMX_REG_ALT		REG_EDX
-	   #define AMX_REG_STK		REG_EBP
-	   #define AMX_REG_DAT		REG_EDI
-	   #define AMX_REG_TMP		REG_ECX
-	   #define AMX_REG_INFO		REG_ESI
-	   #define AMX_REG_FRM		REG_EBX
-	   #define AMX_INFO_FRM		AMX_REG_INFO
-	   #define AMX_INFO_HEAP	4
-	   #define AMX_INFO_RETVAL	12
+	 * #define AMX_REG_PRI		REG_EAX		(done)
+	   #define AMX_REG_ALT		REG_EDX		(done)
+	   #define AMX_REG_STK		REG_EBP		(done)
+	   #define AMX_REG_DAT		REG_EDI		(done)
+	   #define AMX_REG_TMP		REG_ECX		(nothing)
+	   #define AMX_REG_INFO		REG_ESI		(done)
+	   #define AMX_REG_FRM		REG_EBX		(done)
+	   #define AMX_INFO_FRM		AMX_REG_INFO	(done)
+	   #define AMX_INFO_HEAP	4			(done)
+	   #define AMX_INFO_RETVAL	8			(done)
+	   #define AMX_INFO_CONTEXT	12			(done)
 	 *
 	 * The variables we're passed in:
 	 *  sp_context_t *ctx, uint32_t code_idx, cell_t *result
 	 */
 
+	/**
+	 * !NOTE!
+	 * Currently, we do not accept ctx->frm as the new frame pointer.
+	 * Instead, we copy the frame from the stack pointer.
+	 * This is because we do not support resuming or sleeping!
+	 */
 
+	//push ebp
+	//mov ebp, esp
+	IA32_Push_Reg(jit, REG_EBP);
+	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
+
+	//push esi
+	//push edi
+	//push ebx
+	IA32_Push_Reg(jit, REG_ESI);
+	IA32_Push_Reg(jit, REG_EDI);
+	IA32_Push_Reg(jit, REG_EBX);
+
+	//sub esp, 4*4	- allocate info array
+	//mov esi, esp	- save info pointer
+	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
+	IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
+
+	//mov eax, [ebp+16]	- get result pointer
+	//mov [esi+8], eax	- store into info pointer
+	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
+	IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_RETVAL);
+
+	//mov eax, [ebp+8]		- get context
+	//mov [esi+12], eax		- store context into info pointer
+	//mov ecx, [eax+<offs>]	- get heap pointer
+	//mov [esi+4], ecx		- store heap into info pointer
+	//mov edi, [eax+<offs>]	- get data pointer
+	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
+	IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_EAX, AMX_INFO_CONTEXT);
+	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
+	IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ECX, AMX_INFO_HEAP);
+	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data));
+
+	//mov ebp, [eax+<offs>]	- get stack pointer
+	//add ebp, edi			- relocate to data section
+	//mov ebx, ebp			- copy sp to frm
+	//mov ecx, [ebp+12]		- get code index
+	//add ecx, [eax+<offs>] - add code base to index
+	//mov edx, [eax+<offs>]	- get alt
+	//mov eax, [eax+<offs>] - get pri
+	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
+	IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
+	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
+	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12);
+	IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, base));
+	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt));
+	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri));
+
+	/* by now, everything is set up, so we can call into the plugin */
+
+	//call ecx
+	IA32_Call_Rm(jit, REG_ECX);
+
+	/* if the code flow gets to here, there was a normal return */
+	//mov ebp, [esi+8]		- get retval pointer
+	//mov [ebp], eax		- store retval from PRI
+	//mov eax, SP_ERR_NONE	- set no error
+	IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL);
+	IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG);
+	IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE);
+
+	/* where error checking/return functions should go to */
+	jitoffs_t offs_return;
+	if (never_inline)
+	{
+		/* We have to write code assume we're breaking out of a call */
+		//jmp [past the next instruction]
+		//add esp, 4
+		jitoffs_t offs = IA32_Jump_Imm8(jit, 0);
+		offs_return = jit->jit_curpos();
+		IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
+		IA32_Send_Jump8_Here(jit, offs);
+	} else {
+		offs_return = jit->jit_curpos();
+	}
+
+	/* _FOR NOW_ ... 
+	 * We are _not_ going to restore anything that was on the stack.
+	 * This is a tiny, useless optimization based on the fact that 
+	 * BaseContext::Execute() automatically restores our values anyway.
+	 */
+
+	//add esp, 4*4
+	//pop ebx
+	//pop edi
+	//pop esi
+	//pop ebp
+	//ret
+	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
+	IA32_Pop_Reg(jit, REG_EBX);
+	IA32_Pop_Reg(jit, REG_EDI);
+	IA32_Pop_Reg(jit, REG_ESI);
+	IA32_Pop_Reg(jit, REG_EBP);
+	IA32_Return(jit);
+
+	return offs_return;
 }
 
 void Macro_PushN_Addr(JitWriter *jit, int i)
@@ -142,6 +245,7 @@ JITX86::JITX86()
 	OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2;
 	OpAdvTable[OP_CONST] = sizeof(cell_t)*2;
 	OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2;
+	OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2;
 
 	/* instructions with 1 parameter */
 	OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t);
@@ -199,6 +303,7 @@ JITX86::JITX86()
 	OpAdvTable[OP_BOUNDS] = sizeof(cell_t);
 	OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
 	OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t);
+	OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t);
 
 	/* instructions with 0 parameters */
 	OpAdvTable[OP_LOAD_I] = 0;
@@ -261,6 +366,7 @@ JITX86::JITX86()
 	OpAdvTable[OP_BREAK] = 0;
 	OpAdvTable[OP_HEAP_PRI] = 0;
 	OpAdvTable[OP_POP_HEAP_PRI] = 0;
+	OpAdvTable[OP_SYSREQ_PRI] = 0;
 
 	/* opcodes that need relocation */
 	OpAdvTable[OP_CALL] = -2;
diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h
index bfd86db9..64a753c6 100644
--- a/sourcepawn/vm/jit/x86/opcode_helpers.h
+++ b/sourcepawn/vm/jit/x86/opcode_helpers.h
@@ -3,6 +3,19 @@
 
 #include "..\jit_helpers.h"
 
+/**
+ * This outputs the execution function for a plugin.
+ * It also returns the 'return' offset, which is used for 
+ * breaking out of the JIT during runtime.
+ *
+ * If 'never_inline' is true, it outputs slightly different code used for
+ * inlining the error checking routines.
+ */
+jitoffs_t Write_Execute_Function(JitWriter *jit, bool never_inline);
+
+/** 
+ * These are for writing the PushN opcodes.
+ */
 void Macro_PushN_Addr(JitWriter *jit, int i);
 void Macro_PushN_S(JitWriter *jit, int i);
 void Macro_PushN_C(JitWriter *jit, int i);
diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h
index 45ba5d8b..7d0d5a0a 100644
--- a/sourcepawn/vm/jit/x86/x86_macros.h
+++ b/sourcepawn/vm/jit/x86/x86_macros.h
@@ -53,6 +53,7 @@
 #define IA32_XOR_RM_IMM32		0x81	// encoding is /6
 #define IA32_XOR_RM_IMM8		0x83	// encoding is /6
 #define IA32_ADD_RM_REG			0x01	// encoding is /r
+#define IA32_ADD_REG_RM			0x03	// encoding is /r
 #define IA32_ADD_RM_IMM32		0x81	// encoding is /0
 #define IA32_ADD_RM_IMM8		0x83	// encoding is /0
 #define IA32_ADD_EAX_IMM32		0x05	// no extra encoding
@@ -60,7 +61,9 @@
 #define IA32_SUB_RM_IMM8		0x83	// encoding is /5 <imm8>
 #define IA32_SUB_RM_IMM32		0x81	// encoding is /5 <imm32>
 #define IA32_JMP_IMM32			0xE9	// encoding is imm32
+#define IA32_JMP_IMM8			0xEB	// encoding is imm8
 #define IA32_CALL_IMM32			0xE8	// relative call, <imm32>
+#define IA32_CALL_RM			0xFF	// encoding is /2
 #define IA32_MOV_REG_IMM		0xB8	// encoding is +r <imm32>
 #define	IA32_MOV_RM_REG			0x89	// encoding is /r
 #define	IA32_MOV_REG_MEM		0x8B	// encoding is /r
@@ -385,6 +388,13 @@ inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t
 	jit->write_byte(disp);
 }
 
+inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
+{
+	jit->write_ubyte(IA32_ADD_REG_RM);
+	jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
+	jit->write_byte(disp);
+}
+
 inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, 
 							 jit_uint8_t dest, 
 							 jit_int8_t val, 
@@ -652,6 +662,15 @@ inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp)
 	return ptr;
 }
 
+inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp)
+{
+	jitoffs_t ptr;
+	jit->write_ubyte(IA32_JMP_IMM8);
+	ptr = jit->jit_curpos();
+	jit->write_byte(disp);
+	return ptr;
+}
+
 inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp)
 {
 	jitoffs_t ptr;
@@ -671,6 +690,12 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
 	return ptr;
 }
 
+inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg)
+{
+	jit->write_ubyte(IA32_CALL_RM);
+	jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg));
+}
+
 inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target)
 {
 	//save old ptr
diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj
index 4e53d0b5..3bd93d34 100644
--- a/sourcepawn/vm/msvc8/vm.vcproj
+++ b/sourcepawn/vm/msvc8/vm.vcproj
@@ -189,10 +189,6 @@
 			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
-			<File
-				RelativePath="..\sp_vm_base.h"
-				>
-			</File>
 			<File
 				RelativePath="..\sp_vm_basecontext.h"
 				>
@@ -319,6 +315,10 @@
 				RelativePath="..\..\include\sp_vm_api.h"
 				>
 			</File>
+			<File
+				RelativePath="..\..\include\sp_vm_base.h"
+				>
+			</File>
 			<File
 				RelativePath="..\..\include\sp_vm_context.h"
 				>
diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp
index bc38cc82..d64680f1 100644
--- a/sourcepawn/vm/sp_vm_basecontext.cpp
+++ b/sourcepawn/vm/sp_vm_basecontext.cpp
@@ -58,7 +58,18 @@ int BaseContext::Execute(uint32_t public_func, cell_t *result)
 		return err;
 	}
 
-	return vm->ContextExecute(ctx, pubfunc->offs, result);
+	PushCell(ctx->pushcount);
+	ctx->pushcount = 0;
+
+	cell_t save_sp = ctx->sp;
+	cell_t save_hp = ctx->hp;
+
+	err = vm->ContextExecute(ctx, pubfunc->offs, result);
+
+	ctx->sp = save_sp;
+	ctx->hp = save_hp;
+
+	return err;
 }
 
 int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)