sourcepawn/vm/jit/x86/opcode_helpers.cpp
author Borja Ferrer <faluco@alliedmods.net>
Thu Sep 28 19:33:58 2006 +0000 (2006-09-28)
changeset 97 684e06b004f8
parent 93 b00ab8fec541
child 98 a98cd5307c13
permissions -rw-r--r--
helper functions turn
     1 #include <limits.h>
     2 #include <string.h>
     3 #include "jit_x86.h"
     4 #include "opcode_helpers.h"
     5 #include "x86_macros.h"
     6 
     7 int OpAdvTable[OP_NUM_OPCODES];
     8 
     9 jitoffs_t Write_Execute_Function(JitWriter *jit)
    10 {
    11 	/** 
    12 	 * The variables we're passed in:
    13 	 *  sp_context_t *ctx, uint32_t code_idx, cell_t *result
    14 	 */
    15 
    16 	/**
    17 	 * !NOTE!
    18 	 * Currently, we do not accept ctx->frm as the new frame pointer.
    19 	 * Instead, we copy the frame from the stack pointer.
    20 	 * This is because we do not support resuming or sleeping!
    21 	 */
    22 
    23 	//:TODO: FIX THIS FOR THE EBP AND EDI SWITCHING
    24 	//push ebp
    25 	//mov ebp, esp
    26 	IA32_Push_Reg(jit, REG_EBP);
    27 	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
    28 
    29 	//push esi
    30 	//push edi
    31 	//push ebx
    32 	IA32_Push_Reg(jit, REG_ESI);
    33 	IA32_Push_Reg(jit, REG_EDI);
    34 	IA32_Push_Reg(jit, REG_EBX);
    35 
    36 	//sub esp, 4*6	- allocate info array
    37 	//mov esi, esp	- save info pointer
    38 	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG);
    39 	IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
    40 
    41 	/* Initial memory setup */
    42 	//mov eax, [ebp+16]		- get result pointer
    43 	//mov [esi+8], eax		- store into info pointer
    44 	//mov eax, [ebp+8]		- get context
    45 	//mov [esi+12], eax		- store context into info pointer
    46 	//mov ecx, [eax+<offs>]	- get heap pointer
    47 	//mov [esi+4], ecx		- store heap into info pointer
    48 	//mov edi, [eax+<offs>]	- get data pointer
    49 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
    50 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
    51 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
    52 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
    53 	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
    54 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
    55 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data));
    56 
    57 	/* Frame setup */
    58 	//mov ebp, [eax+<offs>]	- get stack pointer
    59 	//add ebp, edi			- relocate to data section
    60 	//mov ebx, ebp			- copy sp to frm
    61 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
    62 	IA32_Add_Rm_Reg(jit, REG_EBP, AMX_REG_STK, AMX_REG_DAT);
    63 	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
    64 
    65 	/* Info memory setup */
    66 	//mov ecx, edi			- copy base of data to temp var
    67 	//add ecx, [eax+<offs>] - add memsize to get stack top
    68 	//mov [esi+16], ecx		- store stack top into info pointer
    69 	//mov ecx, [eax+<offs>] - get heap low
    70 	//mov [esi+20], ecx		- store heap low into info pointer
    71 	IA32_Mov_Reg_Rm(jit, REG_ECX, AMX_REG_DAT, MOD_REG);
    72 	IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
    73 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
    74 	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase));
    75 	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW);
    76 
    77 	/* Remaining needed vars */
    78 	//mov ecx, [ebp+12]		- get code index
    79 	//add ecx, [eax+<offs>] - add code base to index
    80 	//mov edx, [eax+<offs>]	- get alt
    81 	//mov eax, [eax+<offs>] - get pri
    82 	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 12);
    83 	IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
    84 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, REG_EAX, offsetof(sp_context_t, alt));
    85 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, REG_EAX, offsetof(sp_context_t, pri));
    86 
    87 	/* by now, everything is set up, so we can call into the plugin */
    88 	//call ecx
    89 	IA32_Call_Reg(jit, REG_ECX);
    90 
    91 	/* if the code flow gets to here, there was a normal return */
    92 	//mov ebp, [esi+8]		- get retval pointer
    93 	//mov [ebp], eax		- store retval from PRI
    94 	//mov eax, SP_ERR_NONE	- set no error
    95 	IA32_Mov_Reg_Rm_Disp8(jit, REG_EBP, AMX_REG_INFO, AMX_INFO_RETVAL);
    96 	IA32_Mov_Rm_Reg(jit, REG_EBP, AMX_REG_PRI, MOD_MEM_REG);
    97 	IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE);
    98 
    99 	/* save where error checking/halting functions should go to */
   100 	jitoffs_t offs_return;
   101 	CompData *data = (CompData *)jit->data;
   102 	if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
   103 	{
   104 		/* We have to write code assume we're breaking out of a call */
   105 		//jmp [past the next instruction]
   106 		//add esp, 4
   107 		jitoffs_t offs = IA32_Jump_Imm8(jit, 0);
   108 		offs_return = jit->jit_curpos();
   109 		IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
   110 		IA32_Send_Jump8_Here(jit, offs);
   111 	} else {
   112 		offs_return = jit->jit_curpos();
   113 	}
   114 
   115 	/* _FOR NOW_ ... 
   116 	 * We are _not_ going to restore anything that was on the stack.
   117 	 * This is a tiny, useless optimization based on the fact that 
   118 	 * BaseContext::Execute() automatically restores our values anyway.
   119 	 */
   120 
   121 	//add esp, 4*6
   122 	//pop ebx
   123 	//pop edi
   124 	//pop esi
   125 	//pop ebp
   126 	//ret
   127 	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*6, MOD_REG);
   128 	IA32_Pop_Reg(jit, REG_EBX);
   129 	IA32_Pop_Reg(jit, REG_EDI);
   130 	IA32_Pop_Reg(jit, REG_ESI);
   131 	IA32_Pop_Reg(jit, REG_EBP);
   132 	IA32_Return(jit);
   133 
   134 	return offs_return;
   135 }
   136 
   137 void Write_BreakDebug(JitWriter *jit)
   138 {
   139 	//push ecx
   140 	//mov ecx, [esi+ctx]
   141 	//cmp [ecx+dbreak], 0
   142 	//jnz :nocall
   143 	IA32_Push_Reg(jit, AMX_REG_TMP);
   144 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
   145 	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
   146 	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
   147 
   148 	//pushad
   149 	IA32_Pushad(jit);
   150 
   151 	//push [esi+frm]
   152 	//push [ecx+context]
   153 	//mov ecx, [ecx+dbreak]
   154 	//call ecx
   155 	//add esp, 8
   156 	//popad
   157 	IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
   158 	IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context));
   159 	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
   160 	IA32_Call_Reg(jit, AMX_REG_TMP);
   161 	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
   162 	IA32_Popad(jit);
   163 
   164 	//:nocall
   165 	IA32_Send_Jump8_Here(jit, jmp);
   166 	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG);
   167 	IA32_Return(jit);
   168 }
   169 
   170 void Write_Error(JitWriter *jit, int error)
   171 {
   172 	CompData *data = (CompData *)jit->data;
   173 
   174 	/* These are so small that we always inline them! */
   175 	//mov eax, <error>
   176 	//jmp [...jit_return]
   177 	IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
   178 	jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
   179 	IA32_Write_Jump32(jit, jmp, data->jit_return);
   180 }
   181 
   182 void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
   183 {
   184 	//test reg, reg
   185 	//jnz :continue
   186 	//divzero: (write error)
   187 	IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
   188 	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
   189 	if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS))
   190 	{
   191 		//sub esp, 4    - correct stack for returning to non-inlined JIT
   192 		IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
   193 	}
   194 	Write_Error(jit, SP_ERR_DIVIDE_BY_ZERO);
   195 	//continue:
   196 	IA32_Send_Jump8_Here(jit, jmp);
   197 
   198 }
   199 //:TODO: FIX THIS FOR NEW EBP STUFF
   200 void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg, bool firstcall)
   201 {
   202 	CompData *data = (CompData *)jit->data;
   203 
   204 	/* :TODO: Should this be checking for below heaplow?
   205 	 * The old JIT did not.
   206 	 */
   207 
   208 	if (!data->checks)
   209 	{
   210 		return;
   211 	}
   212 
   213 	bool call = false;
   214 	if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
   215 	{
   216 		/* If we're not in the initial generation phase,
   217 		 * Write a call to the actual routine instead.
   218 		 */
   219 		if (!firstcall)
   220 		{
   221 			jitoffs_t call = IA32_Call_Imm32(jit, 0);
   222 			if (reg == REG_EAX)
   223 			{
   224 				IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
   225 			} else if (reg == REG_EDX) {
   226 				IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
   227 			}
   228 			return;
   229 		}
   230 		call = true;
   231 	} else if (firstcall) {
   232 		/* Inline + initial gen == no code */
   233 		return;
   234 	}
   235 
   236 	//cmp reg, [stp]
   237 	//jae memaccess
   238 	//cmp reg, [hea]
   239 	//jb continue
   240 	//lea ecx, [reg+edi]
   241 	//cmp ecx, ebp
   242 	//jae continue
   243 	//memaccess: (write error)
   244 	//continue:
   245 	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP);
   246 	jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
   247 	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
   248 	jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
   249 	IA32_Lea_Reg_DispRegMult(jit, AMX_REG_TMP, reg, AMX_REG_DAT, NOSCALE);
   250 	IA32_Cmp_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
   251 	jitoffs_t jmp3 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
   252 	IA32_Send_Jump8_Here(jit, jmp1);
   253 	Write_Error(jit, SP_ERR_MEMACCESS);
   254 	IA32_Send_Jump8_Here(jit, jmp2);
   255 	IA32_Send_Jump8_Here(jit, jmp3);
   256 	if (call)
   257 	{
   258 		IA32_Return(jit);
   259 	}
   260 }
   261 
   262 void Write_BoundsCheck(JitWriter *jit)
   263 {
   264 	CompData *data = (CompData *)jit->data;
   265 	bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS);
   266 
   267 	/* :TODO: break out on high -O level? */
   268 
   269 	if (!always_inline)
   270 	{
   271 		if (data->jit_bounds)
   272 		{
   273 			/* just generate the call */
   274 			//mov ecx, <val>
   275 			//call <offs>
   276 			IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit->read_cell());
   277 			jitoffs_t call = IA32_Call_Imm32(jit, 0);
   278 			IA32_Write_Jump32(jit, call, data->jit_bounds);
   279 		} else {
   280 			//cmp eax, 0
   281 			//jl :err_bounds
   282 			//cmp eax, ecx
   283 			//jg :err_bounds
   284 			//ret
   285 			IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0);
   286 			jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
   287 			//:TODO: make sure this is right order
   288 			IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_TMP, MOD_REG);
   289 			jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
   290 			IA32_Return(jit);
   291 			IA32_Send_Jump8_Here(jit, jmp1);
   292 			IA32_Send_Jump8_Here(jit, jmp2);
   293 			Write_Error(jit, SP_ERR_ARRAY_BOUNDS);
   294 		}
   295 	} else {
   296 		//cmp eax, 0
   297 		//jl :err_bounds
   298 		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, 0);
   299 		jitoffs_t jmp1 = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
   300 		//cmp eax, <val>
   301 		//jg :err_bounds
   302 		cell_t val = jit->read_cell();
   303 		if (val < SCHAR_MAX && val > SCHAR_MIN)
   304 			IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
   305 		else
   306 			IA32_Cmp_Eax_Imm32(jit, val);
   307 		jitoffs_t jmp2 = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
   308 		//jmp :continue
   309 		jitoffs_t cont = IA32_Jump_Imm8(jit, 0);
   310 		//:err_bounds
   311 		IA32_Send_Jump8_Here(jit, jmp1);
   312 		IA32_Send_Jump8_Here(jit, jmp2);
   313 		Write_Error(jit, SP_ERR_ARRAY_BOUNDS);
   314 		//:continue
   315 		IA32_Send_Jump8_Here(jit, cont);
   316 	}
   317 }
   318 
   319 void Write_CheckMargin_Heap(JitWriter *jit)
   320 {
   321 	CompData *data = (CompData *)jit->data;
   322 
   323 	bool always_inline = ((data->inline_level & JIT_INLINE_ERRORCHECKS) == JIT_INLINE_ERRORCHECKS);
   324 
   325 	if (!always_inline && data->jit_chkmargin_heap)
   326 	{
   327 		/* just generate the call */
   328 		jitoffs_t call = IA32_Call_Imm32(jit, 0);
   329 		IA32_Write_Jump32(jit, call, data->jit_chkmargin_heap);
   330 	} else {
   331 		//mov ecx, [esi+hea]
   332 		//cmp ecx, [esi+hlw]
   333 		//jl :error_heapmin
   334 		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
   335 		IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAPLOW);
   336 		jitoffs_t hm = IA32_Jump_Cond_Imm8(jit, CC_L, 0);
   337 		//lea ecx, [ebp+ecx+STACK_MARGIN]
   338 		//cmp ecx, edi
   339 		// jg :error_heaplow
   340 		//OR
   341 		// ret
   342 		IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
   343 		IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
   344 		jitoffs_t hl = IA32_Jump_Cond_Imm8(jit, CC_G, 0);
   345 		jitoffs_t cont;
   346 		if (always_inline)
   347 		{
   348 			cont = IA32_Jump_Imm8(jit, 0);
   349 		} else {
   350 			IA32_Return(jit);
   351 		}
   352 		//:error_heapmin
   353 		IA32_Send_Jump8_Here(jit, hm);
   354 		Write_Error(jit, SP_ERR_HEAPMIN);
   355 		//:error_heaplow
   356 		IA32_Send_Jump8_Here(jit, hl);
   357 		Write_Error(jit, SP_ERR_HEAPLOW);
   358 		//:continue
   359 		if (!always_inline)
   360 		{
   361 			IA32_Send_Jump8_Here(jit, cont);
   362 		}
   363 	}
   364 }
   365 
   366 void Write_CheckMargin_Stack(JitWriter *jit)
   367 {
   368 	/* this is small, so we always inline it.
   369 	*/
   370 	//cmp edi, [esi+stp]
   371 	//jle :continue
   372 	IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
   373 	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_LE, 0);
   374 	if (!(((CompData *)jit->data)->inline_level & JIT_INLINE_ERRORCHECKS))
   375 	{
   376 		//sub esp, 4	- correct stack for returning to non-inlined JIT
   377 		IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
   378 	}
   379 	Write_Error(jit, SP_ERR_STACKMIN);
   380 	//continue:
   381 	IA32_Send_Jump8_Here(jit, jmp);
   382 }
   383 
   384 void Macro_PushN_Addr(JitWriter *jit, int i)
   385 {
   386 	//push eax
   387 	//mov eax, [esi+frm]
   388 	//loop i times:
   389 	// lea ecx, [eax+<val>]
   390 	// mov [edi-4*i], ecx
   391 	//sub edi, 4*N
   392 	//pop eax
   393 
   394 	cell_t val;
   395 	int n = 1;
   396 	IA32_Push_Reg(jit, AMX_REG_PRI);
   397 	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
   398 	do
   399 	{
   400 		val = jit->read_cell();
   401 		if (val < SCHAR_MAX && val > SCHAR_MIN)
   402 			IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
   403 		else
   404 			IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
   405 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   406 	} while (n++ < i);
   407 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   408 	IA32_Pop_Reg(jit, AMX_REG_PRI);
   409 }
   410 
   411 void Macro_PushN_S(JitWriter *jit, int i)
   412 {
   413 	//loop i times:
   414 	// mov ecx, [ebx+<val>]
   415 	// mov [edi-4*i], ecx
   416 	//sub edi, 4*N
   417 
   418 	cell_t val;
   419 	int n = 1;
   420 	do 
   421 	{
   422 		val = jit->read_cell();
   423 		if (val < SCHAR_MAX && val > SCHAR_MIN)
   424 			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
   425 		else
   426 			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
   427 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   428 	} while (n++ < i);
   429 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   430 }
   431 
   432 void Macro_PushN_C(JitWriter *jit, int i)
   433 {
   434 	//loop i times:
   435 	// mov [edi-4*i], <val>
   436 	//sub edi, 4*N
   437 
   438 	int n = 1;
   439 	do 
   440 	{
   441 		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
   442 	} while (n++ < i);
   443 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   444 }
   445 
   446 void Macro_PushN(JitWriter *jit, int i)
   447 {
   448 	//loop i times:
   449 	// mov ecx, [ebp+<val>]
   450 	// mov [edi-4*i], ecx
   451 	//sub edi, 4*N
   452 
   453 	cell_t val;
   454 	int n = 1;
   455 	do 
   456 	{
   457 		val = jit->read_cell();
   458 		if (val < SCHAR_MAX && val > SCHAR_MIN)
   459 			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
   460 		else
   461 			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
   462 		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   463 	} while (n++ < i);
   464 	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   465 }
   466 
   467 JITX86::JITX86()
   468 {
   469 	memset(OpAdvTable, -1, sizeof(OpAdvTable));
   470 
   471 	/* instructions with 5 parameters */
   472 	OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5;
   473 	OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5;
   474 	OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5;
   475 	OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5;
   476 
   477 	/* instructions with 4 parameters */
   478 	OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4;
   479 	OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4;
   480 	OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4;
   481 	OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4;
   482 
   483 	/* instructions with 3 parameters */
   484 	OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3;
   485 	OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3;
   486 	OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3;
   487 	OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3;
   488 
   489 	/* instructions with 2 parameters */
   490 	OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2;
   491 	OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2;
   492 	OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2;
   493 	OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2;
   494 	OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2;
   495 	OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2;
   496 	OpAdvTable[OP_CONST] = sizeof(cell_t)*2;
   497 	OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2;
   498 	OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2;
   499 
   500 	/* instructions with 1 parameter */
   501 	OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t);
   502 	OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t);
   503 	OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t);
   504 	OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t);
   505 	OpAdvTable[OP_LREF_PRI] = sizeof(cell_t);
   506 	OpAdvTable[OP_LREF_ALT] = sizeof(cell_t);
   507 	OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t);
   508 	OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t);
   509 	OpAdvTable[OP_CONST_PRI] = sizeof(cell_t);
   510 	OpAdvTable[OP_CONST_ALT] = sizeof(cell_t);
   511 	OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t);
   512 	OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t);
   513 	OpAdvTable[OP_STOR_PRI] = sizeof(cell_t);
   514 	OpAdvTable[OP_STOR_ALT] = sizeof(cell_t);
   515 	OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t);
   516 	OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t);
   517 	OpAdvTable[OP_SREF_PRI] = sizeof(cell_t);
   518 	OpAdvTable[OP_SREF_ALT] = sizeof(cell_t);
   519 	OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t);
   520 	OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t);
   521 	OpAdvTable[OP_LIDX_B] = sizeof(cell_t);
   522 	OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t);
   523 	OpAdvTable[OP_PUSH_C] = sizeof(cell_t);
   524 	OpAdvTable[OP_PUSH] = sizeof(cell_t);
   525 	OpAdvTable[OP_PUSH_S] = sizeof(cell_t);
   526 	OpAdvTable[OP_STACK] = sizeof(cell_t);
   527 	OpAdvTable[OP_HEAP] = sizeof(cell_t);
   528 	OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t);
   529 	OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t);
   530 	OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t);
   531 	OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t);
   532 	OpAdvTable[OP_ADD_C] = sizeof(cell_t);
   533 	OpAdvTable[OP_SMUL_C] = sizeof(cell_t);
   534 	OpAdvTable[OP_ZERO] = sizeof(cell_t);
   535 	OpAdvTable[OP_ZERO_S] = sizeof(cell_t);
   536 	OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t);
   537 	OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t);
   538 	OpAdvTable[OP_INC] = sizeof(cell_t);
   539 	OpAdvTable[OP_INC_S] = sizeof(cell_t);
   540 	OpAdvTable[OP_DEC] = sizeof(cell_t);
   541 	OpAdvTable[OP_DEC_S] = sizeof(cell_t);
   542 	OpAdvTable[OP_MOVS] = sizeof(cell_t);
   543 	OpAdvTable[OP_FILL] = sizeof(cell_t);
   544 	OpAdvTable[OP_HALT] = sizeof(cell_t);
   545 	OpAdvTable[OP_BOUNDS] = sizeof(cell_t);
   546 	OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
   547 	OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t);
   548 	OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t);
   549 
   550 	/* instructions with 0 parameters */
   551 	OpAdvTable[OP_LOAD_I] = 0;
   552 	OpAdvTable[OP_STOR_I] = 0;
   553 	OpAdvTable[OP_LIDX] = 0;
   554 	OpAdvTable[OP_IDXADDR] = 0;
   555 	OpAdvTable[OP_MOVE_PRI] = 0;
   556 	OpAdvTable[OP_MOVE_ALT] = 0;
   557 	OpAdvTable[OP_XCHG] = 0;
   558 	OpAdvTable[OP_PUSH_PRI] = 0;
   559 	OpAdvTable[OP_PUSH_ALT] = 0;
   560 	OpAdvTable[OP_POP_PRI] = 0;
   561 	OpAdvTable[OP_POP_ALT] = 0;
   562 	OpAdvTable[OP_PROC] = 0;
   563 	OpAdvTable[OP_RET] = 0;
   564 	OpAdvTable[OP_RETN] = 0;
   565 	OpAdvTable[OP_CALL_PRI] = 0;
   566 	OpAdvTable[OP_SHL] = 0;
   567 	OpAdvTable[OP_SHR] = 0;
   568 	OpAdvTable[OP_SSHR] = 0;
   569 	OpAdvTable[OP_SMUL] = 0;
   570 	OpAdvTable[OP_SDIV] = 0;
   571 	OpAdvTable[OP_SDIV_ALT] = 0;
   572 	OpAdvTable[OP_ADD] = 0;
   573 	OpAdvTable[OP_SUB] = 0;
   574 	OpAdvTable[OP_SUB_ALT] = 0;
   575 	OpAdvTable[OP_AND] = 0;
   576 	OpAdvTable[OP_OR] = 0;
   577 	OpAdvTable[OP_XOR] = 0;
   578 	OpAdvTable[OP_NOT] = 0;
   579 	OpAdvTable[OP_NEG] = 0;
   580 	OpAdvTable[OP_INVERT] = 0;
   581 	OpAdvTable[OP_ZERO_PRI] = 0;
   582 	OpAdvTable[OP_ZERO_ALT] = 0;
   583 	OpAdvTable[OP_SIGN_PRI] = 0;
   584 	OpAdvTable[OP_SIGN_ALT] = 0;
   585 	OpAdvTable[OP_EQ] = 0;
   586 	OpAdvTable[OP_NEQ] = 0;
   587 	OpAdvTable[OP_SLESS] = 0;
   588 	OpAdvTable[OP_SLEQ] = 0;
   589 	OpAdvTable[OP_SGRTR] = 0;
   590 	OpAdvTable[OP_SGEQ] = 0;
   591 	OpAdvTable[OP_INC_PRI] = 0;
   592 	OpAdvTable[OP_INC_ALT] = 0;
   593 	OpAdvTable[OP_INC_I] = 0;
   594 	OpAdvTable[OP_DEC_PRI] = 0;
   595 	OpAdvTable[OP_DEC_ALT] = 0;
   596 	OpAdvTable[OP_DEC_I] = 0;
   597 	OpAdvTable[OP_JUMP_PRI] = 0;
   598 	OpAdvTable[OP_SWAP_PRI] = 0;
   599 	OpAdvTable[OP_SWAP_ALT] = 0;
   600 	OpAdvTable[OP_NOP] = 0;
   601 	OpAdvTable[OP_BREAK] = 0;
   602 	OpAdvTable[OP_HEAP_PRI] = 0;
   603 	OpAdvTable[OP_POP_HEAP_PRI] = 0;
   604 	OpAdvTable[OP_SYSREQ_PRI] = 0;
   605 
   606 	/* opcodes that need relocation */
   607 	OpAdvTable[OP_CALL] = -2;
   608 	OpAdvTable[OP_JUMP] = -2;
   609 	OpAdvTable[OP_JZER] = -2;
   610 	OpAdvTable[OP_JNZ] = -2;
   611 	OpAdvTable[OP_JEQ] = -2;
   612 	OpAdvTable[OP_JNEQ] = -2;
   613 	OpAdvTable[OP_JSLESS] = -2;
   614 	OpAdvTable[OP_JSLEQ] = -2;
   615 	OpAdvTable[OP_JSGRTR] = -2;
   616 	OpAdvTable[OP_JSGEQ] = -2;
   617 	OpAdvTable[OP_SWITCH] = -2;
   618 
   619 	/* opcodes that are totally invalid */
   620 	/* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */
   621 	OpAdvTable[OP_FILE] = -3;
   622 	OpAdvTable[OP_SYMBOL] = -3;
   623 	OpAdvTable[OP_LINE] = -3;
   624 	OpAdvTable[OP_SRANGE] = -3;
   625 	OpAdvTable[OP_SYMTAG] = -3;
   626 	OpAdvTable[OP_SYSREQ_D] = -3;
   627 	OpAdvTable[OP_SYSREQ_ND] = -3;
   628 	OpAdvTable[OP_PUSH_R] = -3;
   629 	OpAdvTable[OP_LODB_I] = -3;
   630 	OpAdvTable[OP_STRB_I] = -3;
   631 	OpAdvTable[OP_LCTRL] = -3;
   632 	OpAdvTable[OP_SCTRL] = -3;
   633 	OpAdvTable[OP_ALIGN_PRI] = -3;
   634 	OpAdvTable[OP_ALIGN_ALT] = -3;
   635 	OpAdvTable[OP_JREL] = -3;
   636 	OpAdvTable[OP_CMPS] = -3;
   637 	OpAdvTable[OP_UMUL] = -3;
   638 	OpAdvTable[OP_UDIV] = -3;
   639 	OpAdvTable[OP_UDIV_ALT] = -3;
   640 	OpAdvTable[OP_LESS] = -3;
   641 	OpAdvTable[OP_LEQ] = -3;
   642 	OpAdvTable[OP_GRTR] = -3;
   643 	OpAdvTable[OP_GEQ] = -3;
   644 	OpAdvTable[OP_JLESS] = -3;
   645 	OpAdvTable[OP_JLEQ] = -3;
   646 	OpAdvTable[OP_JGRTR] = -3;
   647 	OpAdvTable[OP_JGEQ] = -3;
   648 
   649 }