sourcepawn/jit/x86/jit_x86.cpp
author David Anderson <dvander@alliedmods.net>
Mon Mar 12 07:08:05 2007 +0000 (2007-03-12)
changeset 601 fe5b368fcedc
parent 566 7640076104f5
child 602 dcc958866d37
permissions -rw-r--r--
initial import of dynamic native code for both the JIT and plugins
note: dependency resolution is not done yet!
     1 /**
     2  * ================================================================
     3  * SourcePawn (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ================================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <string.h>
    15 #include <stdlib.h>
    16 #include <assert.h>
    17 #include "jit_x86.h"
    18 #include "opcode_helpers.h"
    19 #include "x86_macros.h"
    20 #include "jit_version.h"
    21 
    22 #if defined USE_UNGEN_OPCODES
    23 #include "ungen_opcodes.h"
    24 #endif
    25 
    26 inline void WriteOp_Move_Pri(JitWriter *jit)
    27 {
    28 	//mov eax, edx
    29 	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
    30 }
    31 
    32 inline void WriteOp_Move_Alt(JitWriter *jit)
    33 {
    34 	//mov edx, eax
    35 	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
    36 }
    37 
    38 inline void WriteOp_Xchg(JitWriter *jit)
    39 {
    40 	//xchg eax, edx
    41 	IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT);
    42 }
    43 
    44 inline void WriteOp_Push(JitWriter *jit)
    45 {
    46 	//push stack, DAT offset based
    47 	//sub edi, 4
    48 	//mov ecx, [ebp+<val>]
    49 	//mov [edi], ecx
    50 	cell_t val = jit->read_cell();
    51 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
    52 	//optimize encoding a bit...
    53 	if (val < SCHAR_MAX && val > SCHAR_MIN)
    54 	{
    55 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
    56 	} else {
    57 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
    58 	}
    59 	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
    60 }
    61 
    62 inline void WriteOp_Push_C(JitWriter *jit)
    63 {
    64 	//push stack
    65 	//mov [edi-4], <val>
    66 	//sub edi, 4
    67 	cell_t val = jit->read_cell();
    68 	IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4);
    69 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
    70 }
    71 
    72 inline void WriteOp_Zero(JitWriter *jit)
    73 {
    74 	//mov [ebp+<val>], 0
    75 	cell_t val = jit->read_cell();
    76 	if (val < SCHAR_MAX && val > SCHAR_MIN)
    77 	{
    78 		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val);
    79 	} else {
    80 		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val);
    81 	}
    82 }
    83 
    84 inline void WriteOp_Zero_S(JitWriter *jit)
    85 {
    86 	//mov [ebx+<val>], 0
    87 	cell_t val = jit->read_cell();
    88 	if (val < SCHAR_MAX && val > SCHAR_MIN)
    89 	{
    90 		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val);
    91 	} else {
    92 		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val);
    93 	}
    94 }
    95 
    96 inline void WriteOp_Push_S(JitWriter *jit)
    97 {
    98 	//push stack, FRM offset based
    99 	//sub edi, 4
   100 	//mov ecx, [ebx+<val>]
   101 	//mov [edi], ecx
   102 	cell_t val = jit->read_cell();
   103 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   104 	//optimize encoding a bit...
   105 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   106 	{
   107 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
   108 	} else {
   109 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
   110 	}
   111 	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
   112 }
   113 
   114 inline void WriteOp_Push_Pri(JitWriter *jit)
   115 {
   116 	//mov [edi-4], eax
   117 	//sub edi, 4
   118 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4);
   119 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   120 }
   121 
   122 inline void WriteOp_Push_Alt(JitWriter *jit)
   123 {
   124 	//mov [edi-4], edx
   125 	//sub edi, 4
   126 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4);
   127 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   128 }
   129 
   130 inline void WriteOp_Push2_C(JitWriter *jit)
   131 {
   132 	Macro_PushN_C(jit, 2);
   133 }
   134 
   135 inline void WriteOp_Push3_C(JitWriter *jit)
   136 {
   137 	Macro_PushN_C(jit, 3);
   138 }
   139 
   140 inline void WriteOp_Push4_C(JitWriter *jit)
   141 {
   142 	Macro_PushN_C(jit, 4);
   143 }
   144 
   145 inline void WriteOp_Push5_C(JitWriter *jit)
   146 {
   147 	Macro_PushN_C(jit, 5);
   148 }
   149 
   150 inline void WriteOp_Push2_Adr(JitWriter *jit)
   151 {
   152 	Macro_PushN_Addr(jit, 2);
   153 }
   154 
   155 inline void WriteOp_Push3_Adr(JitWriter *jit)
   156 {
   157 	Macro_PushN_Addr(jit, 3);
   158 }
   159 
   160 inline void WriteOp_Push4_Adr(JitWriter *jit)
   161 {
   162 	Macro_PushN_Addr(jit, 4);
   163 }
   164 
   165 inline void WriteOp_Push5_Adr(JitWriter *jit)
   166 {
   167 	Macro_PushN_Addr(jit, 5);
   168 }
   169 
   170 inline void WriteOp_Push2_S(JitWriter *jit)
   171 {
   172 	Macro_PushN_S(jit, 2);
   173 }
   174 
   175 inline void WriteOp_Push3_S(JitWriter *jit)
   176 {
   177 	Macro_PushN_S(jit, 3);
   178 }
   179 
   180 inline void WriteOp_Push4_S(JitWriter *jit)
   181 {
   182 	Macro_PushN_S(jit, 4);
   183 }
   184 
   185 inline void WriteOp_Push5_S(JitWriter *jit)
   186 {
   187 	Macro_PushN_S(jit, 5);
   188 }
   189 
   190 inline void WriteOp_Push5(JitWriter *jit)
   191 {
   192 	Macro_PushN(jit, 5);
   193 }
   194 
   195 inline void WriteOp_Push4(JitWriter *jit)
   196 {
   197 	Macro_PushN(jit, 4);
   198 }
   199 
   200 inline void WriteOp_Push3(JitWriter *jit)
   201 {
   202 	Macro_PushN(jit, 3);
   203 }
   204 
   205 inline void WriteOp_Push2(JitWriter *jit)
   206 {
   207 	Macro_PushN(jit, 2);
   208 }
   209 
   210 inline void WriteOp_Zero_Pri(JitWriter *jit)
   211 {
   212 	//xor eax, eax
   213 	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
   214 }
   215 
   216 inline void WriteOp_Zero_Alt(JitWriter *jit)
   217 {
   218 	//xor edx, edx
   219 	IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
   220 }
   221 
   222 inline void WriteOp_Add(JitWriter *jit)
   223 {
   224 	//add eax, edx
   225 	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   226 }
   227 
   228 inline void WriteOp_Sub(JitWriter *jit)
   229 {
   230 	//sub eax, edx
   231 	IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   232 }
   233 
   234 inline void WriteOp_Sub_Alt(JitWriter *jit)
   235 {
   236 	//neg eax
   237 	//add eax, edx
   238 	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
   239 	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   240 }
   241 
   242 inline void WriteOp_Proc(JitWriter *jit)
   243 {
   244 	/* align this to four byte boundaries!
   245 	 * This is a decent optimization - x86 likes calls to be properly aligned, otherwise there's an alignment exception
   246 	 * Since all calls are jumped to by relocation, the nops/garbage will never be hit by the runtime process.
   247 	 * Just in case, we guard this memory with INT3 to break into the debugger.
   248 	 */
   249 	jitoffs_t cur_offs = jit->get_outputpos();
   250 	CompData *co = (CompData *)jit->data;
   251 	if (cur_offs % 4)
   252 	{
   253 		cur_offs = 4 - (cur_offs % 4);
   254 		for (unsigned int i=0; i<cur_offs; i++)
   255 		{
   256 			jit->write_ubyte(IA32_INT3);
   257 		}
   258 	}
   259 
   260 	/* Write the info struct about this function */
   261 	jit->write_uint32(JIT_FUNCMAGIC);
   262 	jit->write_uint32(co->func_idx);
   263 
   264 	/* Now we have to backpatch our reloction offset! */
   265 	{
   266 		jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t);
   267 		jitcode_t rebase = ((CompData *)jit->data)->rebase;
   268 		*(jitoffs_t *)((unsigned char  *)rebase + offs) = jit->get_outputpos();
   269 	}
   270 
   271 	/* Lastly, if we're writing, keep track of the function count */
   272 	if (jit->outbase)
   273 	{
   274 		co->func_idx++;
   275 	}
   276 
   277 	//push old frame on stack:
   278 	//mov ecx, [esi+frm]
   279 	//mov [edi-4], ecx
   280 	//sub edi, 8			;extra un-used slot for non-existant CIP
   281 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
   282 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4);
   283 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
   284 	//save frame:
   285 	//mov ecx, edi			- get new frame
   286 	//mov ebx, edi			- store frame back
   287 	//sub ecx, ebp			- relocate local frame
   288 	//mov [esi+frm], ecx
   289 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
   290 	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
   291 	IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
   292 	IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG);
   293 }
   294 
   295 inline void WriteOp_Lidx_B(JitWriter *jit)
   296 {
   297 	cell_t val = jit->read_cell();
   298 	//shl eax, <val>
   299 	//add eax, edx
   300 	//mov eax, [ebp+eax]
   301 	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
   302 	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   303 	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
   304 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
   305 }
   306 
   307 inline void WriteOp_Idxaddr_B(JitWriter *jit)
   308 {
   309 	//shl eax, <val>
   310 	//add eax, edx
   311 	cell_t val = jit->read_cell();
   312 	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
   313 	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   314 }
   315 
   316 inline void WriteOp_Shl(JitWriter *jit)
   317 {
   318 	//mov ecx, edx
   319 	//shl eax, cl
   320 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
   321 	IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
   322 }
   323 
   324 inline void WriteOp_Shr(JitWriter *jit)
   325 {
   326 	//mov ecx, edx
   327 	//shr eax, cl
   328 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
   329 	IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
   330 }
   331 
   332 inline void WriteOp_Sshr(JitWriter *jit)
   333 {
   334 	//mov ecx, edx
   335 	//sar eax, cl
   336 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
   337 	IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
   338 }
   339 
   340 inline void WriteOp_Shl_C_Pri(JitWriter *jit)
   341 {
   342 	//shl eax, <val>
   343 	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
   344 	if (val == 1)
   345 	{
   346 		IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG);
   347 	} else {
   348 		IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
   349 	}
   350 }
   351 
   352 inline void WriteOp_Shl_C_Alt(JitWriter *jit)
   353 {
   354 	//shl edx, <val>
   355 	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
   356 	if (val == 1)
   357 	{
   358 		IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG);
   359 	} else {
   360 		IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
   361 	}
   362 }
   363 
   364 inline void WriteOp_Shr_C_Pri(JitWriter *jit)
   365 {
   366 	//shr eax, <val>
   367 	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
   368 	if (val == 1)
   369 	{
   370 		IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG);
   371 	} else {
   372 		IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
   373 	}
   374 }
   375 
   376 inline void WriteOp_Shr_C_Alt(JitWriter *jit)
   377 {
   378 	//shr edx, <val>
   379 	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
   380 	if (val == 1)
   381 	{
   382 		IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG);
   383 	} else {
   384 		IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
   385 	}
   386 }
   387 
   388 inline void WriteOp_SMul(JitWriter *jit)
   389 {
   390 	//mov ecx, edx
   391 	//imul edx
   392 	//mov edx, ecx
   393 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
   394 	IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG);
   395 	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
   396 }
   397 
   398 inline void WriteOp_Not(JitWriter *jit)
   399 {
   400 	//test eax, eax
   401 	//mov eax, 0
   402 	//sete al
   403 	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
   404 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   405 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
   406 }
   407 
   408 inline void WriteOp_Neg(JitWriter *jit)
   409 {
   410 	//neg eax
   411 	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
   412 }
   413 
   414 inline void WriteOp_Xor(JitWriter *jit)
   415 {
   416 	//xor eax, edx
   417 	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   418 }
   419 
   420 inline void WriteOp_Or(JitWriter *jit)
   421 {
   422 	//or eax, edx
   423 	IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   424 }
   425 
   426 inline void WriteOp_And(JitWriter *jit)
   427 {
   428 	//and eax, edx
   429 	IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   430 }
   431 
   432 inline void WriteOp_Invert(JitWriter *jit)
   433 {
   434 	//not eax
   435 	IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG);
   436 }
   437 
   438 inline void WriteOp_Add_C(JitWriter *jit)
   439 {
   440 	//add eax, <val>
   441 	cell_t val = jit->read_cell();
   442 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   443 		IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
   444 	else
   445 		IA32_Add_Eax_Imm32(jit, val);
   446 }
   447 
   448 inline void WriteOp_SMul_C(JitWriter *jit)
   449 {
   450 	//imul eax, <val>
   451 	cell_t val = jit->read_cell();
   452 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   453 		IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
   454 	else
   455 		IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val);
   456 }
   457 
   458 inline void WriteOp_Sign_Pri(JitWriter *jit)
   459 {
   460 	//shl eax, 24
   461 	//sar eax, 24
   462 	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
   463 	IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
   464 }
   465 
   466 inline void WriteOp_Sign_Alt(JitWriter *jit)
   467 {
   468 	//shl edx, 24
   469 	//sar edx, 24
   470 	IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
   471 	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
   472 }
   473 
   474 inline void WriteOp_Eq(JitWriter *jit)
   475 {
   476 	//cmp eax, edx	; PRI == ALT ?
   477 	//mov eax, 0
   478 	//sete al
   479 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   480 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   481 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
   482 }
   483 
   484 inline void WriteOp_Neq(JitWriter *jit)
   485 {
   486 	//cmp eax, edx	; PRI != ALT ?
   487 	//mov eax, 0
   488 	//setne al
   489 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   490 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   491 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE);
   492 }
   493 
   494 inline void WriteOp_Sless(JitWriter *jit)
   495 {
   496 	//cmp eax, edx	; PRI < ALT ? (signed)
   497 	//mov eax, 0
   498 	//setl al
   499 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   500 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   501 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L);
   502 }
   503 
   504 inline void WriteOp_Sleq(JitWriter *jit)
   505 {
   506 	//cmp eax, edx	; PRI <= ALT ? (signed)
   507 	//mov eax, 0
   508 	//setle al
   509 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   510 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   511 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE);
   512 }
   513 
   514 inline void WriteOp_Sgrtr(JitWriter *jit)
   515 {
   516 	//cmp eax, edx	; PRI > ALT ? (signed)
   517 	//mov eax, 0
   518 	//setg al
   519 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   520 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   521 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G);
   522 }
   523 
   524 inline void WriteOp_Sgeq(JitWriter *jit)
   525 {
   526 	//cmp eax, edx	; PRI >= ALT ? (signed)
   527 	//mov eax, 0
   528 	//setge al
   529 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
   530 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   531 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE);
   532 }
   533 
   534 inline void WriteOp_Eq_C_Pri(JitWriter *jit)
   535 {
   536 	//cmp eax, <val>   ; PRI == value ?
   537 	//mov eax, 0
   538 	//sete al
   539 	cell_t val = jit->read_cell();
   540 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   541 		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
   542 	else
   543 		IA32_Cmp_Eax_Imm32(jit, val);
   544 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
   545 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
   546 }
   547 
   548 inline void WriteOp_Eq_C_Alt(JitWriter *jit)
   549 {
   550 	//xor eax, eax
   551 	//cmp edx, <val>   ; ALT == value ?
   552 	//sete al
   553 	cell_t val = jit->read_cell();
   554 	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
   555 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   556 		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val);
   557 	else
   558 		IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val);
   559 	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
   560 }
   561 
   562 inline void WriteOp_Inc_Pri(JitWriter *jit)
   563 {
   564 	//add eax, 1
   565 	IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
   566 }
   567 
   568 inline void WriteOp_Inc_Alt(JitWriter *jit)
   569 {
   570 	//add edx, 1
   571 	IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
   572 }
   573 
   574 inline void WriteOp_Inc(JitWriter *jit)
   575 {
   576 	//add [ebp+<val>], 1
   577 	cell_t val = jit->read_cell();
   578 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   579 		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
   580 	else
   581 		IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
   582 }
   583 
   584 inline void WriteOp_Inc_S(JitWriter *jit)
   585 {
   586 	//add [ebx+<val>], 1
   587 	cell_t val = jit->read_cell();
   588 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   589 		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
   590 	else
   591 		IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
   592 }
   593 
   594 inline void WriteOp_Inc_I(JitWriter *jit)
   595 {
   596 	//add [ebp+eax], 1
   597 	IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
   598 }
   599 
   600 inline void WriteOp_Dec_Pri(JitWriter *jit)
   601 {
   602 	//sub eax, 1
   603 	IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
   604 }
   605 
   606 inline void WriteOp_Dec_Alt(JitWriter *jit)
   607 {
   608 	//sub edx, 1
   609 	IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
   610 }
   611 
   612 inline void WriteOp_Dec(JitWriter *jit)
   613 {
   614 	//sub [ebp+<val>], 1
   615 	cell_t val = jit->read_cell();
   616 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   617 	{
   618 		IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
   619 	} else {
   620 		IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
   621 	}
   622 }
   623 
   624 inline void WriteOp_Dec_S(JitWriter *jit)
   625 {
   626 	//sub [ebx+<val>], 1
   627 	cell_t val = jit->read_cell();
   628 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   629 	{
   630 		IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
   631 	} else {
   632 		IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
   633 	}
   634 }
   635 
   636 inline void WriteOp_Dec_I(JitWriter *jit)
   637 {
   638 	//sub [ebp+eax], 1
   639 	IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
   640 }
   641 
   642 inline void WriteOp_Load_Pri(JitWriter *jit)
   643 {
   644 	//mov eax, [ebp+<val>]
   645 	cell_t val = jit->read_cell();
   646 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   647 	{
   648 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
   649 	} else {
   650 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
   651 	}
   652 }
   653 
   654 inline void WriteOp_Load_Alt(JitWriter *jit)
   655 {
   656 	//mov edx, [ebp+<val>]
   657 	cell_t val = jit->read_cell();
   658 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   659 	{
   660 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
   661 	} else {
   662 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
   663 	}
   664 }
   665 
   666 inline void WriteOp_Load_S_Pri(JitWriter *jit)
   667 {
   668 	//mov eax, [ebx+<val>]
   669 	cell_t val = jit->read_cell();
   670 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   671 	{
   672 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
   673 	} else {
   674 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
   675 	}
   676 }
   677 
   678 inline void WriteOp_Load_S_Alt(JitWriter *jit)
   679 {
   680 	//mov edx, [ebx+<val>]
   681 	cell_t val = jit->read_cell();
   682 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   683 	{
   684 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
   685 	} else {
   686 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
   687 	}
   688 }
   689 
   690 inline void WriteOp_Lref_Pri(JitWriter *jit)
   691 {
   692 	//mov eax, [ebp+<val>]
   693 	//mov eax, [ebp+eax]
   694 	cell_t val = jit->read_cell();
   695 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   696 	{
   697 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
   698 	} else {
   699 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
   700 	}
   701 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
   702 }
   703 
   704 inline void WriteOp_Lref_Alt(JitWriter *jit)
   705 {
   706 	//mov edx, [ebp+<val>]
   707 	//mov edx, [ebp+edx]
   708 	cell_t val = jit->read_cell();
   709 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   710 	{
   711 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
   712 	} else {
   713 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
   714 	}
   715 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
   716 }
   717 
   718 inline void WriteOp_Lref_S_Pri(JitWriter *jit)
   719 {
   720 	//mov eax, [ebx+<val>]
   721 	//mov eax, [ebp+eax]
   722 	cell_t val = jit->read_cell();
   723 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   724 	{
   725 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
   726 	} else {
   727 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
   728 	}
   729 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
   730 }
   731 
   732 inline void WriteOp_Lref_S_Alt(JitWriter *jit)
   733 {
   734 	//mov edx, [ebx+<val>]
   735 	//mov edx, [ebp+edx]
   736 	cell_t val = jit->read_cell();
   737 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   738 	{
   739 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
   740 	} else {
   741 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
   742 	}
   743 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
   744 }
   745 
   746 inline void WriteOp_Const_Pri(JitWriter *jit)
   747 {
   748 	//mov eax, <val>
   749 	cell_t val = jit->read_cell();
   750 	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val);
   751 }
   752 
   753 inline void WriteOp_Const_Alt(JitWriter *jit)
   754 {
   755 	//mov edx, <val>
   756 	cell_t val = jit->read_cell();
   757 	IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val);
   758 }
   759 
   760 inline void WriteOp_Addr_Pri(JitWriter *jit)
   761 {
   762 	//mov eax, [esi+frm]
   763 	//add eax, <val>
   764 	cell_t val = jit->read_cell();
   765 	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
   766 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   767 	{
   768 		IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
   769 	} else {
   770 		IA32_Add_Eax_Imm32(jit, val);
   771 	}
   772 }
   773 
   774 inline void WriteOp_Addr_Alt(JitWriter *jit)
   775 {
   776 	//mov edx, [esi+frm]
   777 	//add edx, <val>
   778 	cell_t val = jit->read_cell();
   779 	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG);
   780 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   781 	{
   782 		IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG);
   783 	} else {
   784 		IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG);
   785 	}
   786 }
   787 
   788 inline void WriteOp_Stor_Pri(JitWriter *jit)
   789 {
   790 	//mov [ebp+<val>], eax
   791 	cell_t val = jit->read_cell();
   792 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   793 	{
   794 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val);
   795 	} else {
   796 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val);
   797 	}
   798 }
   799 
   800 inline void WriteOp_Stor_Alt(JitWriter *jit)
   801 {
   802 	//mov [ebp+<val>], edx
   803 	cell_t val = jit->read_cell();
   804 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   805 	{
   806 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val);
   807 	} else {
   808 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val);
   809 	}
   810 }
   811 
   812 inline void WriteOp_Stor_S_Pri(JitWriter *jit)
   813 {
   814 	//mov [ebx+<val>], eax
   815 	cell_t val = jit->read_cell();
   816 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   817 	{
   818 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val);
   819 	} else {
   820 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val);
   821 	}
   822 }
   823 
   824 inline void WriteOp_Stor_S_Alt(JitWriter *jit)
   825 {
   826 	//mov [ebx+<val>], edx
   827 	cell_t val = jit->read_cell();
   828 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   829 	{
   830 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val);
   831 	} else {
   832 		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val);
   833 	}
   834 }
   835 
   836 inline void WriteOp_Idxaddr(JitWriter *jit)
   837 {
   838 	//lea eax, [edx+4*eax]
   839 	IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
   840 }
   841 
   842 inline void WriteOp_Sref_Pri(JitWriter *jit)
   843 {
   844 	//mov ecx, [ebp+<val>]
   845 	//mov [ebp+ecx], eax
   846 	cell_t val = jit->read_cell();
   847 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   848 	{
   849 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
   850 	} else {
   851 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
   852 	}
   853 	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
   854 }
   855 
   856 inline void WriteOp_Sref_Alt(JitWriter *jit)
   857 {
   858 	//mov ecx, [ebp+<val>]
   859 	//mov [ebp+ecx], edx
   860 	cell_t val = jit->read_cell();
   861 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   862 	{
   863 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
   864 	} else {
   865 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
   866 	}
   867 	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
   868 }
   869 
   870 inline void WriteOp_Sref_S_Pri(JitWriter *jit)
   871 {
   872 	//mov ecx, [ebx+<val>]
   873 	//mov [ebp+ecx], eax
   874 	cell_t val = jit->read_cell();
   875 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   876 	{
   877 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
   878 	} else {
   879 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
   880 	}
   881 	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
   882 }
   883 
   884 inline void WriteOp_Sref_S_Alt(JitWriter *jit)
   885 {
   886 	//mov ecx, [ebx+<val>]
   887 	//mov [ebp+ecx], edx
   888 	cell_t val = jit->read_cell();
   889 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   890 	{
   891 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
   892 	} else {
   893 		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
   894 	}
   895 	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
   896 }
   897 
   898 inline void WriteOp_Pop_Pri(JitWriter *jit)
   899 {
   900 	//mov eax, [edi]
   901 	//add edi, 4
   902 	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
   903 	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   904 }
   905 
   906 inline void WriteOp_Pop_Alt(JitWriter *jit)
   907 {
   908 	//mov edx, [edi]
   909 	//add edi, 4
   910 	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
   911 	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   912 }
   913 
   914 inline void WriteOp_Swap_Pri(JitWriter *jit)
   915 {
   916 	//add [edi], eax
   917 	//sub eax, [edi]
   918 	//add [edi], eax
   919 	//neg eax
   920 	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
   921 	IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
   922 	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
   923 	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
   924 }
   925 
   926 inline void WriteOp_Swap_Alt(JitWriter *jit)
   927 {
   928 	//add [edi], edx
   929 	//sub edx, [edi]
   930 	//add [edi], edx
   931 	//neg edx
   932 	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
   933 	IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
   934 	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
   935 	IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG);
   936 }
   937 
   938 inline void WriteOp_PushAddr(JitWriter *jit)
   939 {
   940 	//mov ecx, [esi+frm]	;get address (offset from frame)
   941 	//sub edi, 4
   942 	//add ecx, <val>
   943 	//mov [edi], ecx
   944 	cell_t val = jit->read_cell();
   945 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
   946 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
   947 	if (val < SCHAR_MAX && val > SCHAR_MIN)
   948 	{
   949 		IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG);
   950 	} else {
   951 		IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG);
   952 	}
   953 	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
   954 }
   955 
   956 inline void WriteOp_Movs(JitWriter *jit)
   957 {
   958 	//cld
   959 	//push esi
   960 	//push edi
   961 	//lea esi, [ebp+eax]
   962 	//lea edi, [ebp+edx]
   963 	//if dword:
   964 	// mov ecx, dword
   965 	// rep movsd
   966 	//if byte:
   967 	// mov ecx, byte
   968 	// rep movsb
   969 	//pop edi
   970 	//pop esi
   971 	cell_t val = jit->read_cell();
   972 	unsigned int dwords = val >> 2;
   973 	unsigned int bytes = val & 0x3;
   974 
   975 	IA32_Cld(jit);
   976 	IA32_Push_Reg(jit, REG_ESI);
   977 	IA32_Push_Reg(jit, REG_EDI);
   978 	IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
   979 	IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
   980 	if (dwords)
   981 	{
   982 		IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords);
   983 		IA32_Rep(jit);
   984 		IA32_Movsd(jit);
   985 	}
   986 	if (bytes)
   987 	{
   988 		IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes);
   989 		IA32_Rep(jit);
   990 		IA32_Movsb(jit);
   991 	}
   992 	IA32_Pop_Reg(jit, REG_EDI);
   993 	IA32_Pop_Reg(jit, REG_ESI);
   994 }
   995 
   996 inline void WriteOp_Fill(JitWriter *jit)
   997 {
   998 	//push edi
   999 	//lea edi, [ebp+edx]
  1000 	//mov ecx, <val> >> 2
  1001 	//cld
  1002 	//rep stosd
  1003 	//pop edi
  1004 	unsigned int val = jit->read_cell() >> 2;
  1005 
  1006 	IA32_Push_Reg(jit, REG_EDI);
  1007 	IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
  1008 	IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
  1009 	IA32_Cld(jit);
  1010 	IA32_Rep(jit);
  1011 	IA32_Stosd(jit);
  1012 	IA32_Pop_Reg(jit, REG_EDI);
  1013 }
  1014 
  1015 inline void WriteOp_GenArray(JitWriter *jit, bool autozero)
  1016 {
  1017 	cell_t val = jit->read_cell();
  1018 	if (val == 1)
  1019 	{
  1020 		/* flat array.  we can generate this without indirection tables. */
  1021 		/* Note that we can overwrite ALT because technically STACK should be destroying ALT */
  1022 		//mov edx, [esi+info.heap]
  1023 		//mov ecx, [edi]
  1024 		//mov [edi], edx			;store base of array into stack
  1025 		//lea edx, [edx+ecx*4]		;get the final new heap pointer
  1026 		//mov [esi+info.heap], edx	;store heap pointer back
  1027 		//add edx, ebp				;relocate
  1028 		//cmp edx, edi				;compare against stack pointer
  1029 		//jae :error				;error out if not enough space
  1030 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
  1031 		IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
  1032 		IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
  1033 		IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4);
  1034 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP);
  1035 		IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG);
  1036 		IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG);
  1037 		IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow);
  1038 
  1039 		WriteOp_Tracker_Push_Reg(jit, REG_ECX);
  1040 
  1041 		if (autozero)
  1042 		{
  1043 			/* Zero out the array - inline a quick fill */
  1044 			//push eax				;save pri
  1045 			//push edi				;save stk
  1046 			//xor eax, eax			;zero source
  1047 			//mov edi, [edi]		;get heap ptr out of the stack
  1048 			//add edi, ebp			;relocate
  1049 			//cld					;clear direction flag
  1050 			//rep stosd				;copy (note: ECX is sane from above)
  1051 			//pop edi				;pop stk
  1052 			//pop eax				;pop pri
  1053 			IA32_Push_Reg(jit, REG_EAX);
  1054 			IA32_Push_Reg(jit, REG_EDI);
  1055 			IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG);
  1056 			IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG);
  1057 			IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
  1058 			IA32_Cld(jit);
  1059 			IA32_Rep(jit);
  1060 			IA32_Stosd(jit);
  1061 			IA32_Pop_Reg(jit, REG_EDI);
  1062 			IA32_Pop_Reg(jit, REG_EAX);
  1063 		}
  1064 	} else {
  1065 		//mov ecx, num_dims
  1066 		//mov edx, 0/1
  1067 		//call [genarray]
  1068 		IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val);
  1069 		if (autozero)
  1070 		{
  1071 			IA32_Mov_Reg_Imm32(jit, REG_EDX, 1);
  1072 		} else {
  1073 			IA32_Mov_Reg_Imm32(jit, REG_EDX, 0);
  1074 		}
  1075 		jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1076 		IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_genarray);
  1077 	}
  1078 }
  1079 
  1080 inline void WriteOp_Load_Both(JitWriter *jit)
  1081 {
  1082 	WriteOp_Load_Pri(jit);
  1083 	WriteOp_Load_Alt(jit);
  1084 }
  1085 
  1086 inline void WriteOp_Load_S_Both(JitWriter *jit)
  1087 {
  1088 	WriteOp_Load_S_Pri(jit);
  1089 	WriteOp_Load_S_Alt(jit);
  1090 }
  1091 
  1092 inline void WriteOp_Const(JitWriter *jit)
  1093 {
  1094 	//mov [ebp+<addr>], <val>
  1095 	cell_t addr = jit->read_cell();
  1096 	cell_t val = jit->read_cell();
  1097 	if (addr < SCHAR_MAX && addr > SCHAR_MIN)
  1098 	{
  1099 		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr);
  1100 	} else {
  1101 		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr);
  1102 	}
  1103 }
  1104 
  1105 inline void WriteOp_Const_S(JitWriter *jit)
  1106 {
  1107 	//mov [ebx+<offs>], <val>
  1108 	cell_t offs = jit->read_cell();
  1109 	cell_t val = jit->read_cell();
  1110 	if (offs < SCHAR_MAX && offs > SCHAR_MIN)
  1111 	{
  1112 		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs);
  1113 	} else {
  1114 		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs);
  1115 	}
  1116 }
  1117 
  1118 inline void WriteOp_Load_I(JitWriter *jit)
  1119 {
  1120 	//mov eax, [ebp+eax]
  1121 	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
  1122 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
  1123 }
  1124 
  1125 inline void WriteOp_Lodb_I(JitWriter *jit)
  1126 {
  1127 	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
  1128 
  1129 	//mov eax, [ebp+eax]
  1130 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
  1131 
  1132 	//and eax, <bitmask>
  1133 	cell_t val = jit->read_cell();
  1134 	switch(val)
  1135 	{
  1136 	case 1:
  1137 		{
  1138 			IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);
  1139 			break;
  1140 		}
  1141 	case 2:
  1142 		{
  1143 			IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);
  1144 			break;
  1145 		}
  1146 	}
  1147 }
  1148 
  1149 inline void WriteOp_Stor_I(JitWriter *jit)
  1150 {
  1151 	//mov [ebp+edx], eax
  1152 	Write_Check_VerifyAddr(jit, AMX_REG_ALT);
  1153 	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
  1154 }
  1155 
  1156 inline void WriteOp_Strb_I(JitWriter *jit)
  1157 {
  1158 	Write_Check_VerifyAddr(jit, AMX_REG_ALT);
  1159 	//mov [ebp+edx], eax
  1160 	cell_t val = jit->read_cell();
  1161 	switch (val)
  1162 	{
  1163 	case 1:
  1164 		{
  1165 			IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
  1166 			break;
  1167 		}
  1168 	case 2:
  1169 		{
  1170 			IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
  1171 			break;
  1172 		}
  1173 	case 4:
  1174 		{
  1175 			IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
  1176 			break;
  1177 		}
  1178 	}
  1179 }
  1180 
  1181 inline void WriteOp_Lidx(JitWriter *jit)
  1182 {
  1183 	//lea eax, [edx+4*eax]
  1184 	//mov eax, [ebp+eax]
  1185 	IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
  1186 	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
  1187 	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
  1188 }
  1189 
  1190 inline void WriteOp_Stack(JitWriter *jit)
  1191 {
  1192 	//add edi, <val>
  1193 	cell_t val = jit->read_cell();
  1194 	if (val < SCHAR_MAX && val > SCHAR_MIN)
  1195 	{
  1196 		IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG);
  1197 	} else {
  1198 		IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG);
  1199 	}
  1200 
  1201 	if (val > 0)
  1202 	{
  1203 		Write_CheckStack_Min(jit);
  1204 	} else if (val < 0) {
  1205 		Write_CheckStack_Low(jit);
  1206 	}
  1207 }
  1208 
  1209 inline void WriteOp_Heap(JitWriter *jit)
  1210 {
  1211 	//mov edx, [esi+hea]
  1212 	//add [esi+hea], <val>
  1213 	cell_t val = jit->read_cell();
  1214 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
  1215 	if (val < SCHAR_MAX && val > SCHAR_MIN)
  1216 	{
  1217 		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP);
  1218 	} else {
  1219 		IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP);
  1220 	}
  1221 
  1222 	/* NOTE: Backwards from op.stack */
  1223 	if (val > 0)
  1224 	{
  1225 		Write_CheckHeap_Low(jit);
  1226 	} else if (val < 0) {
  1227 		Write_CheckHeap_Min(jit);
  1228 	}
  1229 }
  1230 
  1231 inline void WriteOp_SDiv(JitWriter *jit)
  1232 {
  1233 	//mov ecx, edx
  1234 	//mov edx, eax
  1235 	//sar edx, 31
  1236 	//idiv ecx
  1237 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
  1238 	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
  1239 	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
  1240 	Write_Check_DivZero(jit, AMX_REG_TMP);
  1241 	IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
  1242 }
  1243 
  1244 inline void WriteOp_SDiv_Alt(JitWriter *jit)
  1245 {
  1246 	//mov ecx, eax
  1247 	//mov eax, edx
  1248 	//sar edx, 31
  1249 	//idiv ecx
  1250 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
  1251 	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1252 	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
  1253 	Write_Check_DivZero(jit, AMX_REG_TMP);
  1254 	IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
  1255 }
  1256 
  1257 inline void WriteOp_Retn(JitWriter *jit)
  1258 {
  1259 	//mov ebx, [edi+4]		- get old frm
  1260 	//add edi, 8			- pop stack
  1261 	//mov [esi+frm], ebx	- restore frame pointer
  1262 	//add ebx, ebp			- relocate
  1263 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4);
  1264 	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
  1265 	IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG);
  1266 	IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG);
  1267 
  1268 	/* pop params */
  1269 	//mov ecx, [edi]
  1270 	//lea edi, [edi+ecx*4+4] 
  1271 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
  1272 	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4);
  1273 
  1274 	//ret					- return (EIP on real stack!)
  1275 	IA32_Return(jit);
  1276 }
  1277 
  1278 inline void WriteOp_Call(JitWriter *jit)
  1279 {
  1280 	cell_t offs = jit->read_cell();
  1281 
  1282 	jitoffs_t jmp = IA32_Call_Imm32(jit, 0);
  1283 	IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false));
  1284 }
  1285 
  1286 inline void WriteOp_Bounds(JitWriter *jit)
  1287 {
  1288 	cell_t val = jit->read_cell();
  1289 	
  1290 	//cmp eax, <val>
  1291 	//ja :error
  1292 	if (val < SCHAR_MAX && val > SCHAR_MIN)
  1293 	{
  1294 		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
  1295 	} else {
  1296 		IA32_Cmp_Eax_Imm32(jit, val);
  1297 	}
  1298 	IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds);
  1299 }
  1300 
  1301 inline void WriteOp_Halt(JitWriter *jit)
  1302 {
  1303 	//mov ecx, [esi+ret]
  1304 	//mov [ecx], eax
  1305 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL);
  1306 	IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG);
  1307 	
  1308 	/* :TODO: 
  1309 	 * We don't support sleeping or halting with weird values.
  1310 	 * So we're omitting the mov eax <val> that was here.
  1311 	 */
  1312 	jit->read_cell();
  1313 
  1314 	CompData *data = (CompData *)jit->data;
  1315 	IA32_Jump_Imm32_Abs(jit, data->jit_return);
  1316 }
  1317 
  1318 inline void WriteOp_Break(JitWriter *jit)
  1319 {
  1320 	CompData *data = (CompData *)jit->data;
  1321 	if (data->debug)
  1322 	{
  1323 		//jit->write_ubyte(IA32_INT3);
  1324 		//mov ecx, <cip>
  1325 		jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0);
  1326 		jitoffs_t save = jit->get_outputpos();
  1327 		jit->set_outputpos(wr);
  1328 		jit->write_uint32((uint32_t)(wr));
  1329 		jit->set_outputpos(save);
  1330 		
  1331 		wr = IA32_Call_Imm32(jit, 0);
  1332 		IA32_Write_Jump32(jit, wr, data->jit_break);
  1333 	}
  1334 }
  1335 
  1336 inline void WriteOp_Jump(JitWriter *jit)
  1337 {
  1338 	//jmp <offs>
  1339 	cell_t amx_offs = jit->read_cell();
  1340 	IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false));
  1341 }
  1342 
  1343 inline void WriteOp_Jzer(JitWriter *jit)
  1344 {
  1345 	//test eax, eax
  1346 	//jz <target>
  1347 	cell_t target = jit->read_cell();
  1348 	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
  1349 	IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false));
  1350 }
  1351 
  1352 inline void WriteOp_Jnz(JitWriter *jit)
  1353 {
  1354 	//test eax, eax
  1355 	//jnz <target>
  1356 	cell_t target = jit->read_cell();
  1357 	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
  1358 	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, RelocLookup(jit, target, false));
  1359 }
  1360 
  1361 inline void WriteOp_Jeq(JitWriter *jit)
  1362 {
  1363 	//cmp eax, edx
  1364 	//je <target>
  1365 	cell_t target = jit->read_cell();
  1366 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1367 	IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false));
  1368 }
  1369 
  1370 inline void WriteOp_Jneq(JitWriter *jit)
  1371 {
  1372 	//cmp eax, edx
  1373 	//jne <target>
  1374 	cell_t target = jit->read_cell();
  1375 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1376 	IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false));
  1377 }
  1378 
  1379 inline void WriteOp_Jsless(JitWriter *jit)
  1380 {
  1381 	//cmp eax, edx
  1382 	//jl <target>
  1383 	cell_t target = jit->read_cell();
  1384 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1385 	IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false));
  1386 }
  1387 
  1388 inline void WriteOp_Jsleq(JitWriter *jit)
  1389 {
  1390 	//cmp eax, edx
  1391 	//jle <target>
  1392 	cell_t target = jit->read_cell();
  1393 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1394 	IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false));
  1395 }
  1396 
  1397 inline void WriteOp_JsGrtr(JitWriter *jit)
  1398 {
  1399 	//cmp eax, edx
  1400 	//jg <target>
  1401 	cell_t target = jit->read_cell();
  1402 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1403 	IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false));
  1404 }
  1405 
  1406 inline void WriteOp_JsGeq(JitWriter *jit)
  1407 {
  1408 	//cmp eax, edx
  1409 	//jge <target>
  1410 	cell_t target = jit->read_cell();
  1411 	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
  1412 	IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false));
  1413 }
  1414 
  1415 inline void WriteOp_Switch(JitWriter *jit)
  1416 {
  1417 	cell_t offs = jit->read_cell();
  1418 	cell_t *tbl = (cell_t *)((char *)jit->inbase + offs + sizeof(cell_t));
  1419 
  1420 	struct casetbl
  1421 	{
  1422 		cell_t val;
  1423 		cell_t offs;
  1424 	};
  1425 
  1426 	/* Read the number of cases, then advance by one */
  1427 	cell_t num_cases = *tbl++;
  1428 	if (!num_cases)
  1429 	{
  1430 		/* Special treatment for 0 cases */
  1431 		//jmp <default>
  1432 		IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false));
  1433 	} else {
  1434 		/* Check if the case layout is fully sequential */
  1435 		casetbl *iter = (casetbl *)(tbl + 1);
  1436 		casetbl *cases = iter;
  1437 		cell_t first = iter[0].val;
  1438 		cell_t last = first;
  1439 		bool sequential = true;
  1440 		for (cell_t i=1; i<num_cases; i++)
  1441 		{
  1442 			if (iter[i].val != ++last)
  1443 			{
  1444 				sequential = false;
  1445 				break;
  1446 			}
  1447 		}
  1448 		/* Time to generate. 
  1449 		 * First check whether the bounds are correct: if (a < LOW || a > HIGH)
  1450 		 * This check is valid for both sequential and non-sequential.
  1451 		 */
  1452 		cell_t low_bound = cases[0].val;
  1453 		if (low_bound != 0)
  1454 		{
  1455 			/* negate it so we'll get a lower bound of 0 */
  1456 			//lea ecx, [eax-<LOWER_BOUND>]
  1457 			low_bound = -low_bound;
  1458 			if (low_bound > SCHAR_MIN && low_bound < SCHAR_MAX)
  1459 			{
  1460 				IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
  1461 			} else {
  1462 				IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
  1463 			}
  1464 		}
  1465 		cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val);
  1466 		//cmp ecx, <UPPER BOUND BOUND>
  1467 		if (high_bound > SCHAR_MIN && high_bound < SCHAR_MAX)
  1468 		{
  1469 			IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound);
  1470 		} else {
  1471 			IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound);
  1472 		}
  1473 		//ja <default case>
  1474 		IA32_Jump_Cond_Imm32_Abs(jit, CC_A, RelocLookup(jit, *tbl, false));
  1475 
  1476 		/**
  1477 		 * Now we've taken the default case out of the way, it's time to do the
  1478 		 * full check, which is different for sequential vs. non-sequential.
  1479 		 */
  1480 		if (sequential)
  1481 		{
  1482 			/* we're now theoretically guaranteed to be jumping to a correct offset.
  1483 			 * ECX still has the correctly bound offset in it, luckily!
  1484 			 * thus, we simply need to relocate ECX and store the cases.
  1485 			 */
  1486 			//lea ecx, [ecx*4]
  1487 			//add ecx, <case table start>
  1488 			IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0);
  1489 			jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG);
  1490 			IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG);
  1491 			/* The case table starts here.  Go back and write the output pointer. */
  1492 			jitoffs_t cur_pos = jit->get_outputpos();
  1493 			jit->set_outputpos(tbl_offs);
  1494 			jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos));
  1495 			jit->set_outputpos(cur_pos);
  1496 			//now we can write the case table, finally!
  1497 			jit_uint32_t base = (jit_uint32_t)jit->outbase;
  1498 			for (cell_t i=0; i<num_cases; i++)
  1499 			{
  1500 				jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false));
  1501 			}
  1502 		} else {
  1503 			/* The slow version.  Go through each case and generate a check.
  1504 			 * In the future we should replace case tables of more than ~8 cases with a
  1505 			 * hash table lookup.
  1506 			 * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case,
  1507 			 *  but only if we're under N cases or so!
  1508 			 * :THOUGHT: Write out a static btree lookup :)
  1509 			 */
  1510 			cell_t val;
  1511 			for (cell_t i=0; i<num_cases; i++)
  1512 			{
  1513 				val = cases[i].val;
  1514 				//cmp eax, <val> OR cmp al, <val>
  1515 				if (val > SCHAR_MIN && val < SCHAR_MAX)
  1516 				{
  1517 					IA32_Cmp_Al_Imm8(jit, val);
  1518 				} else {
  1519 					IA32_Cmp_Eax_Imm32(jit, cases[i].val);
  1520 				}
  1521 				IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false));
  1522 			}
  1523 			/* After all this, jump to the default case! */
  1524 			IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false));
  1525 		}
  1526 	}
  1527 }
  1528 
  1529 inline void WriteOp_Casetbl(JitWriter *jit)
  1530 {
  1531 	/* do nothing here, switch does all ze work */
  1532 	cell_t num_cases = jit->read_cell();
  1533 
  1534 	/* Two cells per case, one extra case for the default jump */
  1535 	num_cases = (num_cases * 2) + 1;
  1536 	jit->inptr += num_cases;
  1537 }
  1538 
  1539 inline void WriteOp_Sysreq_C(JitWriter *jit)
  1540 {
  1541 	/* store the number of parameters on the stack, 
  1542 	 * and store the native index as well.
  1543 	 */
  1544 	cell_t native_index = jit->read_cell();
  1545 
  1546 	if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num)
  1547 	{
  1548 		((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM;
  1549 		return;
  1550 	}
  1551 
  1552 	//mov ecx, <native_index>
  1553 	IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index);
  1554 
  1555 	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1556 	IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c);
  1557 }
  1558 
  1559 inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit)
  1560 {
  1561 	/* store the number of parameters on the stack, 
  1562 	 * and store the native index as well.
  1563 	 */
  1564 	cell_t native_index = jit->read_cell();
  1565 	cell_t num_params = jit->read_cell();
  1566 	
  1567 	if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num)
  1568 	{
  1569 		((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM;
  1570 		return;
  1571 	}
  1572 
  1573 	//mov eax, <num_params>
  1574 	//mov ecx, <native_index>
  1575 	IA32_Mov_Reg_Imm32(jit, REG_EAX, num_params);
  1576 	IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index);
  1577 
  1578 	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1579 	IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n);
  1580 }
  1581 
  1582 inline void WriteOp_Sysreq_N(JitWriter *jit)
  1583 {
  1584 	/* The big daddy of opcodes. */
  1585 	cell_t native_index = jit->read_cell();
  1586 	cell_t num_params = jit->read_cell();
  1587 	CompData *data = (CompData *)jit->data;
  1588 
  1589 	if ((uint32_t)native_index >= data->plugin->info.natives_num)
  1590 	{
  1591 		data->error_set = SP_ERROR_INSTRUCTION_PARAM;
  1592 		return;
  1593 	}
  1594 
  1595 	/* store the number of parameters on the stack */
  1596 	//mov [edi-4], num_params
  1597 	//sub edi, 4
  1598 	IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4);
  1599 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
  1600 
  1601 	/* save registers we will need */
  1602 	//push edx
  1603 	IA32_Push_Reg(jit, AMX_REG_ALT);
  1604 
  1605 	/* push some callback stuff */
  1606 	//push edi		; stack
  1607 	//push <native>	; native index
  1608 	IA32_Push_Reg(jit, AMX_REG_STK);
  1609 	if (native_index < SCHAR_MAX && native_index > SCHAR_MIN)
  1610 	{
  1611 		IA32_Push_Imm8(jit, (jit_int8_t)native_index);
  1612 	} else {
  1613 		IA32_Push_Imm32(jit, native_index);
  1614 	}
  1615 
  1616 	/* Relocate stack, heap, frm information, then store back */
  1617 	//mov eax, [esi+context]
  1618 	//mov ecx, [esi+hea]
  1619 	//sub edi, ebp
  1620 	//mov [eax+hp], ecx
  1621 	//mov ecx, [esi]
  1622 	//mov [eax+sp], edi
  1623 	//mov [eax+frm], ecx
  1624 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
  1625 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
  1626 	IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
  1627 	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
  1628 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
  1629 	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
  1630 	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
  1631 
  1632 	/* finally, push the last parameter and make the call */
  1633 	//push eax		; context
  1634 	//call NativeCallback
  1635 	IA32_Push_Reg(jit, REG_EAX);
  1636 	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1637 	if (!data->debug)
  1638 	{
  1639 		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
  1640 	} else {
  1641 		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
  1642 	}
  1643 	
  1644 	/* check for errors */
  1645 	//mov ecx, [esi+context]
  1646 	//cmp [ecx+err], 0
  1647 	//jnz :error
  1648 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
  1649 	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
  1650 	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
  1651 
  1652 	/* restore what we damaged */
  1653 	//add esp, 4*3
  1654 	//add edi, ebp
  1655 	//pop edx
  1656 	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
  1657 	IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
  1658 	IA32_Pop_Reg(jit, AMX_REG_ALT);
  1659 
  1660 	/* pop the stack.  do not check the margins.
  1661 	 * Note that this is not a true macro - we don't bother to
  1662 	 * set ALT here because nothing will be using it.
  1663 	 */
  1664 	num_params++;
  1665 	num_params *= 4;
  1666 	//add edi, <val*4+4>
  1667 	if (num_params < SCHAR_MAX && num_params > SCHAR_MIN)
  1668 	{
  1669 		IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG);
  1670 	} else {
  1671 		IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG);
  1672 	}
  1673 }
  1674 
  1675 inline void WriteOp_Tracker_Push_C(JitWriter *jit)
  1676 {
  1677 	CompData *data = (CompData *)jit->data;
  1678 	cell_t val = jit->read_cell();
  1679 
  1680 	/* Save registers that may be damaged by the call */
  1681 	//push eax
  1682 	//push edx
  1683 	IA32_Push_Reg(jit, AMX_REG_PRI);
  1684 	IA32_Push_Reg(jit, AMX_REG_ALT);
  1685 
  1686 	/* Get the context ptr, push it and call the check */
  1687 	//mov eax, [esi+context]
  1688 	//push eax
  1689 	//call JIT_VerifyOrAllocateTracker
  1690 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
  1691 	IA32_Push_Reg(jit, REG_EAX);
  1692 	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1693 	IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
  1694 
  1695 	/* Check for errors */
  1696 	//cmp eax, 0
  1697 	//jnz :error
  1698 	IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
  1699 	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
  1700 
  1701 	/* Restore */
  1702 	//pop eax
  1703 	IA32_Pop_Reg(jit, REG_EAX);
  1704 
  1705 	/* Push the value into the stack and increment pCur */
  1706 	//mov edx, [eax+vm[]]
  1707 	//mov ecx, [edx+pcur]
  1708 	//add [edx+pcur], 4
  1709 	//mov [ecx], <val>*4	; we want the count in bytes not in cells
  1710 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
  1711 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
  1712 	IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
  1713 	IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG);
  1714 
  1715 	/* Restore PRI & ALT */
  1716 	//pop edx
  1717 	//pop eax
  1718 	IA32_Pop_Reg(jit, AMX_REG_ALT);
  1719 	IA32_Pop_Reg(jit, AMX_REG_PRI);
  1720 }
  1721 
  1722 inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit)
  1723 {
  1724 	CompData *data = (CompData *)jit->data;
  1725 
  1726 	/* Save registers that may be damaged by the call */
  1727 	//push eax
  1728 	//push edx
  1729 	IA32_Push_Reg(jit, AMX_REG_PRI);
  1730 	IA32_Push_Reg(jit, AMX_REG_ALT);
  1731 
  1732 	/* Get the context ptr, push it and call the check */
  1733 	//mov eax, [esi+context]
  1734 	//push eax
  1735 	//call JIT_VerifyLowBoundTracker
  1736 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
  1737 	IA32_Push_Reg(jit, REG_EAX);
  1738 	jitoffs_t call = IA32_Call_Imm32(jit, 0);
  1739 	IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyLowBoundTracker);
  1740 
  1741 	/* Check for errors */
  1742 	//cmp eax, 0
  1743 	//jnz :error
  1744 	IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
  1745 	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
  1746 
  1747 	/* Restore */
  1748 	//pop eax
  1749 	IA32_Pop_Reg(jit, REG_EAX);
  1750 
  1751 	/* Pop the value from the stack and decrease the heap by it*/
  1752 	//mov edx, [eax+vm[]]
  1753 	//sub [edx+pcur], 4
  1754 	//mov ecx, [edx+pcur]
  1755 	//mov ecx, [ecx]
  1756 	//sub [esi+hea], ecx
  1757 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
  1758 	IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
  1759 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
  1760 	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG);
  1761 	IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP);
  1762 
  1763 	Write_CheckHeap_Min(jit);
  1764 
  1765 	/* Restore PRI & ALT */
  1766 	//pop edx
  1767 	//pop eax
  1768 	IA32_Pop_Reg(jit, AMX_REG_ALT);
  1769 	IA32_Pop_Reg(jit, AMX_REG_PRI);
  1770 }
  1771 
  1772 inline void WriteOp_Stradjust_Pri(JitWriter *jit)
  1773 {
  1774 	//add eax, 4
  1775 	//sar eax, 2
  1776 	IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 4, MOD_REG);
  1777 	IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 2, MOD_REG);
  1778 }
  1779 
  1780 /*************************************************
  1781  *************************************************
  1782  * JIT PROPER ************************************
  1783  * The rest from now on is the JIT engine        *
  1784  *************************************************
  1785  *************************************************/
  1786 
  1787 cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  1788 {
  1789 	sp_native_t *native = &ctx->natives[native_idx];
  1790 
  1791 	ctx->n_idx = native_idx;
  1792 	
  1793 	/* Technically both aren't needed, I guess */
  1794 	if (native->status == SP_NATIVE_UNBOUND)
  1795 	{
  1796 		ctx->n_err = SP_ERROR_INVALID_NATIVE;
  1797 		return 0;
  1798 	}
  1799 
  1800 	return native->pfn(ctx->context, params);
  1801 }
  1802 
  1803 static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
  1804 {
  1805 	sp_context_t *ctx = pCtx->GetContext();
  1806 	ctx->n_err = SP_ERROR_INVALID_NATIVE;
  1807 
  1808 	return 0;
  1809 }
  1810 
  1811 cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
  1812 {
  1813 	cell_t save_sp = ctx->sp;
  1814 	cell_t save_hp = ctx->hp;
  1815 
  1816 	ctx->n_idx = native_idx;
  1817 
  1818 	if (ctx->hp < ctx->heap_base)
  1819 	{
  1820 		ctx->n_err = SP_ERROR_HEAPMIN;
  1821 		return 0;
  1822 	}
  1823 
  1824 	if (ctx->hp + STACK_MARGIN > ctx->sp)
  1825 	{
  1826 		ctx->n_err = SP_ERROR_STACKLOW;
  1827 		return 0;
  1828 	}
  1829 
  1830 	if ((uint32_t)ctx->sp >= ctx->mem_size)
  1831 	{
  1832 		ctx->n_err = SP_ERROR_STACKMIN;
  1833 		return 0;
  1834 	}
  1835 
  1836 	cell_t result = NativeCallback(ctx, native_idx, params);
  1837 	
  1838 	if (ctx->n_err != SP_ERROR_NONE)
  1839 	{
  1840 		return result;
  1841 	}
  1842 
  1843 	if (save_sp != ctx->sp)
  1844 	{
  1845 		ctx->n_err = SP_ERROR_STACKLEAK;
  1846 		return result;
  1847 	} else if (save_hp != ctx->hp) {
  1848 		ctx->n_err = SP_ERROR_HEAPLEAK;
  1849 		return result;
  1850 	}
  1851 
  1852 	return result;
  1853 }
  1854 
  1855 jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
  1856 {
  1857 	if (jit->outptr)
  1858 	{
  1859 		CompData *data = (CompData *)jit->data;
  1860 		if (relative)
  1861 		{
  1862 			/* The actual offset is EIP relative. We need to relocate it.
  1863 			 * Note that this assumes that we're pointing to the next op.
  1864 			 */
  1865 			pcode_offs += jit->get_inputpos();
  1866 		}
  1867 		/* Offset must always be 1)positive and 2)less than or equal to the codesize */
  1868 		assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->codesize);
  1869 		/* Do the lookup in the native dictionary. */
  1870 		return *(jitoffs_t *)(data->rebase + pcode_offs);
  1871 	} else {
  1872 		return 0;
  1873 	}
  1874 }
  1875 
  1876 void WriteErrorRoutines(CompData *data, JitWriter *jit)
  1877 {
  1878 	data->jit_error_divzero = jit->get_outputpos();
  1879 	Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO);
  1880 
  1881 	data->jit_error_stacklow = jit->get_outputpos();
  1882 	Write_SetError(jit, SP_ERROR_STACKLOW);
  1883 
  1884 	data->jit_error_stackmin = jit->get_outputpos();
  1885 	Write_SetError(jit, SP_ERROR_STACKMIN);
  1886 
  1887 	data->jit_error_bounds = jit->get_outputpos();
  1888 	Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS);
  1889 
  1890 	data->jit_error_memaccess = jit->get_outputpos();
  1891 	Write_SetError(jit, SP_ERROR_MEMACCESS);
  1892 
  1893 	data->jit_error_heaplow = jit->get_outputpos();
  1894 	Write_SetError(jit, SP_ERROR_HEAPLOW);
  1895 
  1896 	data->jit_error_heapmin = jit->get_outputpos();
  1897 	Write_SetError(jit, SP_ERROR_HEAPMIN);
  1898 
  1899 	data->jit_error_array_too_big = jit->get_outputpos();
  1900 	Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG);
  1901 
  1902 	data->jit_extern_error = jit->get_outputpos();
  1903 	Write_GetError(jit);
  1904 }
  1905 
  1906 sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
  1907 {
  1908 	CompData *data = (CompData *)co;
  1909 	sp_plugin_t *plugin = data->plugin;
  1910 
  1911 	/* The first phase is to browse */
  1912 	uint8_t *code = plugin->pcode;
  1913 	uint8_t *end_cip = plugin->pcode + plugin->pcode_size;
  1914 	OPCODE op;
  1915 
  1916 	/*********************************************
  1917 	 * FIRST PASS (medium load): writer.outbase is NULL, getting size only
  1918 	 * SECOND PASS (heavy load!!): writer.outbase is valid and output is written
  1919 	 *********************************************/
  1920 
  1921 	JitWriter writer;
  1922 	JitWriter *jit = &writer;
  1923 	cell_t *endptr = (cell_t *)(end_cip);
  1924 	uint32_t codemem = 0;
  1925 
  1926 	/* Initial code is written "blank,"
  1927 	 * so we can check the exact memory usage.
  1928 	 */
  1929 	data->codesize = plugin->pcode_size;
  1930 	writer.data = data;
  1931 	writer.inbase = (cell_t *)code;
  1932 	writer.outptr = NULL;
  1933 	writer.outbase = NULL;
  1934 	/* Allocate relocation.  One extra cell for final CIP. */
  1935 	data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size + sizeof(cell_t));
  1936 
  1937 	/* We will jump back here for second pass */
  1938 jit_rewind:
  1939 	/* Initialize pass vars */
  1940 	writer.inptr = writer.inbase;
  1941 	data->jit_verify_addr_eax = 0;
  1942 	data->jit_verify_addr_edx = 0;
  1943 
  1944 	/* Write the prologue of the JIT */
  1945 	data->jit_return = Write_Execute_Function(jit);
  1946 
  1947 	/* Write the SYSREQ.N opcode if we need to */
  1948 	if (!(data->inline_level & JIT_INLINE_NATIVES))
  1949 	{
  1950 		data->jit_sysreq_n = jit->get_outputpos();
  1951 		WriteOp_Sysreq_N_Function(jit);
  1952 	}
  1953 
  1954 	/* Write the debug section if we need it */
  1955 	if (data->debug == true)
  1956 	{
  1957 		data->jit_break = jit->get_outputpos();
  1958 		Write_BreakDebug(jit);
  1959 	}
  1960 
  1961 	/* Plugins compiled with -O0 will need this! */
  1962 	data->jit_sysreq_c = jit->get_outputpos();
  1963 	WriteOp_Sysreq_C_Function(jit);
  1964 
  1965 	data->jit_genarray = jit->get_outputpos();
  1966 	WriteIntrinsic_GenArray(jit);
  1967 
  1968 	/* Write error checking routines that are called to */
  1969 	if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
  1970 	{
  1971 		data->jit_verify_addr_eax = jit->get_outputpos();
  1972 		Write_Check_VerifyAddr(jit, REG_EAX);
  1973 	
  1974 		data->jit_verify_addr_edx = jit->get_outputpos();
  1975 		Write_Check_VerifyAddr(jit, REG_EDX);
  1976 	}
  1977 
  1978 	/* Actual code generation! */
  1979 	if (writer.outbase == NULL)
  1980 	{
  1981 		/* First Pass - find codesize and resolve relocation */
  1982 		jitoffs_t pcode_offs;
  1983 		jitoffs_t native_offs;
  1984 
  1985 		for (; writer.inptr < endptr;)
  1986 		{
  1987 			/* Store the native offset into the rebase memory.
  1988 			 * This large chunk of memory lets us do an instant lookup
  1989 			 * based on an original pcode offset.
  1990 			 */
  1991 			pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code);
  1992 			native_offs = jit->get_outputpos();
  1993 			*((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs;
  1994 
  1995 			/* Now read the opcode and continue. */
  1996 			op = (OPCODE)writer.read_cell();
  1997 			switch (op)
  1998 			{
  1999 				#include "opcode_switch.inc"
  2000 			}
  2001 			/* Check for errors.  This should only happen in the first pass. */
  2002 			if (data->error_set != SP_ERROR_NONE)
  2003 			{
  2004 				*err = data->error_set;
  2005 				AbortCompilation(co);
  2006 				return NULL;
  2007 			}
  2008 		}
  2009 		/* Write these last because error jumps should be unpredicted, and thus forward */
  2010 		WriteErrorRoutines(data, jit);
  2011 
  2012 		/* Write the final CIP to the last position in the reloc array */
  2013 		pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code);
  2014 		native_offs = jit->get_outputpos();
  2015 		*((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs;
  2016 
  2017 		/* the total codesize is now known! */
  2018 		codemem = writer.get_outputpos();
  2019 		writer.outbase = (jitcode_t)engine->ExecAlloc(codemem);
  2020 		writer.outptr = writer.outbase;
  2021 		/* go back for third pass */
  2022 		goto jit_rewind;
  2023 	} else {
  2024 		/*******
  2025 		 * THIRD PASS - write opcode info
  2026 		 *******/
  2027 		for (; writer.inptr < endptr;)
  2028 		{
  2029 			op = (OPCODE)writer.read_cell();
  2030 			switch (op)
  2031 			{
  2032 				#include "opcode_switch.inc"
  2033 			}
  2034 		}
  2035 		/* Write these last because error jumps should be unpredicted, and thus forward */
  2036 		WriteErrorRoutines(data, jit);
  2037 	}
  2038 
  2039 	/*************
  2040 	 * FOURTH PASS - Context Setup
  2041 	 *************/
  2042 
  2043 	sp_context_t *ctx = new sp_context_t;
  2044 	memset(ctx, 0, sizeof(sp_context_t));
  2045 
  2046 	/* setup  basics */
  2047 	ctx->codebase = writer.outbase;
  2048 	ctx->plugin = plugin;
  2049 	ctx->vmbase = this;
  2050 	ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0);
  2051 
  2052 	/* setup memory */
  2053 	ctx->memory = new uint8_t[plugin->memory];
  2054 	memcpy(ctx->memory, plugin->data, plugin->data_size);
  2055 	ctx->mem_size = plugin->memory;
  2056 	ctx->heap_base = plugin->data_size;
  2057 	ctx->hp = ctx->heap_base;
  2058 	ctx->sp = ctx->mem_size - sizeof(cell_t);
  2059 
  2060 	const char *strbase = plugin->info.stringbase;
  2061 	uint32_t max, iter;
  2062 
  2063 	/* relocate public info */
  2064 	if ((max = plugin->info.publics_num))
  2065 	{
  2066 		ctx->publics = new sp_public_t[max];
  2067 		for (iter=0; iter<max; iter++)
  2068 		{
  2069 			ctx->publics[iter].name = strbase + plugin->info.publics[iter].name;
  2070 			ctx->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false);
  2071 			/* Encode the ID as a straight code offset */
  2072 			ctx->publics[iter].funcid = (ctx->publics[iter].code_offs << 1);
  2073 		}
  2074 	}
  2075 
  2076 	/* relocate pubvar info */
  2077 	if ((max = plugin->info.pubvars_num))
  2078 	{
  2079 		uint8_t *dat = ctx->memory;
  2080 		ctx->pubvars = new sp_pubvar_t[max];
  2081 		for (iter=0; iter<max; iter++)
  2082 		{
  2083 			ctx->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name;
  2084 			ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address);
  2085 		}
  2086 	}
  2087 
  2088 	/* relocate native info */
  2089 	if ((max = plugin->info.natives_num))
  2090 	{
  2091 		ctx->natives = new sp_native_t[max];
  2092 		for (iter=0; iter<max; iter++)
  2093 		{
  2094 			ctx->natives[iter].name = strbase + plugin->info.natives[iter].name;
  2095 			ctx->natives[iter].pfn = &InvalidNative;
  2096 			ctx->natives[iter].status = SP_NATIVE_UNBOUND;
  2097 		}
  2098 	}
  2099 
  2100 	/**
  2101 	 * If we're debugging, make sure we copy the necessary info.
  2102 	 */
  2103 	if (data->debug)
  2104 	{
  2105 		strbase = plugin->debug.stringbase;
  2106 		
  2107 		/* relocate files */
  2108 		max = plugin->debug.files_num;
  2109 		ctx->files = new sp_debug_file_t[max];
  2110 		for (iter=0; iter<max; iter++)
  2111 		{
  2112 			ctx->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false);
  2113 			ctx->files[iter].name = strbase + plugin->debug.files[iter].name;
  2114 		}
  2115 
  2116 		/* relocate lines */
  2117 		max = plugin->debug.lines_num;
  2118 		ctx->lines = new sp_debug_line_t[max];
  2119 		for (iter=0; iter<max; iter++)
  2120 		{
  2121 			ctx->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false);
  2122 			ctx->lines[iter].line = plugin->debug.lines[iter].line;
  2123 		}
  2124 
  2125 		/* relocate arrays */
  2126 		sp_fdbg_symbol_t *sym;
  2127 		sp_fdbg_arraydim_t *arr;
  2128 		uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
  2129 		
  2130 		max = plugin->debug.syms_num;
  2131 		ctx->symbols = new sp_debug_symbol_t[max];
  2132 		for (iter=0; iter<max; iter++)
  2133 		{
  2134 			sym = (sp_fdbg_symbol_t *)cursor;
  2135 
  2136 			/**
  2137 			 * @brief There is an "issue" where the compiler will give totally bogus code 
  2138 			 * address because codegeneration is still being calculated.  A simple fix for 
  2139 			 * this is to coerce the codestart value to 0 when it's invalid.
  2140 			 */
  2141 			if (sym->codestart > data->codesize)
  2142 			{
  2143 				ctx->symbols[iter].codestart = 0;
  2144 			} else {
  2145 				ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false);
  2146 			}
  2147 			if (sym->codeend > data->codesize)
  2148 			{
  2149 				ctx->symbols[iter].codeend = data->codesize;
  2150 			} else {
  2151 				ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false);
  2152 			}
  2153 			ctx->symbols[iter].name = strbase + sym->name;
  2154 			ctx->symbols[iter].sym = sym;
  2155 
  2156 			if (sym->dimcount > 0)
  2157 			{
  2158 				cursor += sizeof(sp_fdbg_symbol_t);
  2159 				arr = (sp_fdbg_arraydim_t *)cursor;
  2160 				ctx->symbols[iter].dims = arr;
  2161 				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
  2162 				continue;
  2163 			}
  2164 
  2165 			ctx->symbols[iter].dims = NULL;
  2166 			cursor += sizeof(sp_fdbg_symbol_t);
  2167 		}
  2168 	}
  2169 
  2170 	tracker_t *trk = new tracker_t;
  2171 	ctx->vm[JITVARS_TRACKER] = trk;
  2172 	trk->pBase = (ucell_t *)malloc(1024);
  2173 	trk->pCur = trk->pBase;
  2174 	trk->size = 1024 / sizeof(cell_t);
  2175 
  2176 	functracker_t *fnc = new functracker_t;
  2177 	ctx->vm[JITVARS_FUNCINFO] = fnc;
  2178 	ctx->vm[JITVARS_REBASE] = data->rebase;
  2179 	fnc->code_size = codemem;
  2180 	fnc->num_functions = data->func_idx;
  2181 
  2182 	/* clean up relocation+compilation memory */
  2183 	data->rebase = NULL;
  2184 	AbortCompilation(co);
  2185 
  2186 	*err = SP_ERROR_NONE;
  2187 
  2188 	return ctx;
  2189 }
  2190 
  2191 SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
  2192 {
  2193 	JitWriter jw;
  2194 	JitWriter *jit = &jw;
  2195 
  2196 	jw.outbase = NULL;
  2197 	jw.outptr = NULL;
  2198 	jw.data = NULL;
  2199 
  2200 	/* First pass, calculate size */
  2201 rewind:
  2202 	//push pData		;push pData
  2203 	//push [esp+12]		;push params
  2204 	//push [esp+12]		;push ctx
  2205 	//call [callback]	;invoke the meta-callback
  2206 	//add esp, 12		;restore the stack
  2207 	//ret				;return
  2208 	IA32_Push_Imm32(jit, (jit_int32_t)pData);
  2209 	IA32_Push_Rm_Disp8_ESP(jit, 12);
  2210 	IA32_Push_Rm_Disp8_ESP(jit, 12);
  2211 	uint32_t call = IA32_Call_Imm32(jit, 0);
  2212 	IA32_Write_Jump32_Abs(jit, call, (void *)callback);
  2213 	IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG);
  2214 	IA32_Return(jit);
  2215 
  2216 	if (jw.outbase == NULL)
  2217 	{
  2218 		/* Second pass: Actually write */
  2219 		jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos());
  2220 		if (!jw.outbase)
  2221 		{
  2222 			return NULL;
  2223 		}
  2224 		jw.outptr = jw.outbase;
  2225 	
  2226 		goto rewind;
  2227 	}
  2228 	
  2229 	return (SPVM_NATIVE_FUNC)jw.outbase;
  2230 }
  2231 
  2232 void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
  2233 {
  2234 	engine->ExecFree(func);
  2235 }
  2236 
  2237 const char *JITX86::GetVMName()
  2238 {
  2239 	return "JIT (x86)";
  2240 }
  2241 
  2242 int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result)
  2243 {
  2244 	typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *);
  2245  	CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase;
  2246 	return fn(ctx, code_idx, result);
  2247 }
  2248 
  2249 void JITX86::FreeContext(sp_context_t *ctx)
  2250 {
  2251 	engine->ExecFree(ctx->codebase);
  2252 	delete [] ctx->memory;
  2253 	delete [] ctx->files;
  2254 	delete [] ctx->lines;
  2255 	delete [] ctx->natives;
  2256 	delete [] ctx->publics;
  2257 	delete [] ctx->pubvars;
  2258 	delete [] ctx->symbols;
  2259 	engine->BaseFree(ctx->vm[JITVARS_REBASE]);
  2260 	free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
  2261 	delete (tracker_t *)ctx->vm[JITVARS_TRACKER];	
  2262 	delete ctx;
  2263 }
  2264 
  2265 ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin)
  2266 {
  2267 	CompData *data = new CompData;
  2268 
  2269 	data->plugin = plugin;
  2270 	data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
  2271 	data->error_set = SP_ERROR_NONE;
  2272 
  2273 	return data;
  2274 }
  2275 
  2276 void JITX86::AbortCompilation(ICompilation *co)
  2277 {
  2278 	if (((CompData *)co)->rebase)
  2279 	{
  2280 		engine->BaseFree(((CompData *)co)->rebase);
  2281 	}
  2282 	delete (CompData *)co;
  2283 }
  2284 
  2285 bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char *val)
  2286 {
  2287 	CompData *data = (CompData *)co;
  2288 
  2289 	if (strcmp(key, "debug") == 0)
  2290 	{
  2291 		if ((atoi(val) == 1) || !strcmp(val, "yes"))
  2292 		{
  2293 			data->debug = true;
  2294 		} else {
  2295 			data->debug = false;
  2296 		}
  2297 		if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG))
  2298 		{
  2299 			data->debug = false;
  2300 			return false;
  2301 		}
  2302 		return true;
  2303 	}
  2304 
  2305 	return false;
  2306 }
  2307 
  2308 unsigned int JITX86::GetAPIVersion()
  2309 {
  2310 	return SOURCEPAWN_VM_API_VERSION;
  2311 }
  2312 
  2313 bool JITX86::FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
  2314 {
  2315 	uint8_t *rebase = (uint8_t *)ctx->vm[JITVARS_REBASE];
  2316 
  2317 	/* Is this within the pcode bounds? */
  2318 	if (code_addr >= ctx->plugin->pcode_size - sizeof(uint32_t))
  2319 	{
  2320 		return false;
  2321 	}
  2322 
  2323 	/* Relocate this */
  2324 	code_addr = *(jitoffs_t *)(rebase + code_addr);
  2325 
  2326 	/* Check if this is in the relocation bounds */
  2327 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
  2328 	if (code_addr >= fnc->code_size)
  2329 	{
  2330 		return false;
  2331 	}
  2332 
  2333 	/* Get the function info and sanity check */
  2334 	funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
  2335 	if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
  2336 	{
  2337 		return false;
  2338 	}
  2339 
  2340 	if (result)
  2341 	{
  2342 		*result = f->index;
  2343 	}
  2344 
  2345 	return true;
  2346 }
  2347 
  2348 bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
  2349 {
  2350 	/* Check if this is in the relocation bounds */
  2351 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
  2352 	if (code_addr >= fnc->code_size)
  2353 	{
  2354 		return false;
  2355 	}
  2356 
  2357 	/* Get the function info and sanity check */
  2358 	funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
  2359 	if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
  2360 	{
  2361 		return false;
  2362 	}
  2363 
  2364 	if (result)
  2365 	{
  2366 		*result = f->index;
  2367 	}
  2368 
  2369 	return true;
  2370 }
  2371 
  2372 unsigned int JITX86::FunctionCount(const sp_context_t *ctx)
  2373 {
  2374 	functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
  2375 
  2376 	return fnc->num_functions;
  2377 }
  2378 
  2379 const char *JITX86::GetVersionString()
  2380 {
  2381 	return SVN_FULL_VERSION;
  2382 }
  2383 
  2384 const char *JITX86::GetCPUOptimizations()
  2385 {
  2386 	return "Generic 80486";
  2387 }