sourcepawn/jit/x86/opcode_helpers.cpp
changeset 3977 fca2b54741ca
parent 3976 bc77cfde7c5c
child 3978 5bdc0f106c05
     1.1 --- a/sourcepawn/jit/x86/opcode_helpers.cpp	Thu Aug 08 09:40:23 2013 -0700
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,706 +0,0 @@
     1.4 -/**
     1.5 - * vim: set ts=4 :
     1.6 - * =============================================================================
     1.7 - * SourceMod
     1.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     1.9 - * =============================================================================
    1.10 - *
    1.11 - * This program is free software; you can redistribute it and/or modify it under
    1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 - * Free Software Foundation.
    1.14 - * 
    1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 - * details.
    1.19 - *
    1.20 - * You should have received a copy of the GNU General Public License along with
    1.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 - *
    1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 - * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 - * or <http://www.sourcemod.net/license.php>.
    1.31 - *
    1.32 - * Version: $Id$
    1.33 - */
    1.34 -
    1.35 -#include <limits.h>
    1.36 -#include <string.h>
    1.37 -#include <stdlib.h>
    1.38 -#include "jit_x86.h"
    1.39 -#include "opcode_helpers.h"
    1.40 -#include "x86_macros.h"
    1.41 -
    1.42 -jitoffs_t Write_Execute_Function(JitWriter *jit)
    1.43 -{
    1.44 -	/** 
    1.45 -	 * The variables we're passed in:
    1.46 -	 *  void *vars[], void *entry_func
    1.47 -	 */
    1.48 -
    1.49 -	/**
    1.50 -	 * !NOTE!
    1.51 -	 * Currently, we do not accept ctx->frm as the new frame pointer.
    1.52 -	 * Instead, we copy the frame from the stack pointer.
    1.53 -	 * This is because we do not support resuming or sleeping!
    1.54 -	 */
    1.55 -
    1.56 -	//push ebp
    1.57 -	//mov ebp, esp
    1.58 -	IA32_Push_Reg(jit, REG_EBP);
    1.59 -	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
    1.60 -
    1.61 -	//push esi
    1.62 -	//push edi
    1.63 -	//push ebx
    1.64 -	IA32_Push_Reg(jit, REG_ESI);
    1.65 -	IA32_Push_Reg(jit, REG_EDI);
    1.66 -	IA32_Push_Reg(jit, REG_EBX);
    1.67 -
    1.68 -	/* Prep us for doing the real work */
    1.69 -	//mov esi, [ebp+param0]			;get vars
    1.70 -	//mov ecx, [ebp+param1]			;get entry addr
    1.71 -	//mov eax, [esi+MEMORY]			;get memory base
    1.72 -	//mov edx, [esi+CONTEXT]		;get context
    1.73 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_ESI, REG_EBP, 8 + 4*0);
    1.74 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 8 + 4*1);
    1.75 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_ESI, AMX_INFO_MEMORY);
    1.76 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_CONTEXT);
    1.77 -
    1.78 -	/* Set up run-time registers */
    1.79 -	//mov edi, [edx+SP]				;non-reloc SP
    1.80 -	//add edi, eax					;reloc SP
    1.81 -	//mov ebp, eax					;DAT
    1.82 -	//mov ebx, edi					;reloc FRM
    1.83 -	//mov [esi+NSTACK], esp			;save ESP
    1.84 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EDX, offsetof(sp_context_t, sp));
    1.85 -	IA32_Add_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_REG);
    1.86 -	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_EAX, MOD_REG);
    1.87 -	IA32_Mov_Reg_Rm(jit, REG_EBX, REG_EDI, MOD_REG);
    1.88 -	IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ESP, AMX_INFO_NSTACK);
    1.89 -
    1.90 -	/* by now, everything is set up, so we can call into the plugin */
    1.91 -	//call ecx
    1.92 -	IA32_Call_Reg(jit, REG_ECX);
    1.93 -
    1.94 -	/* if the code flow gets to here, there was a normal return */
    1.95 -	//mov ecx, [esi+RETVAL]			;get retval pointer
    1.96 -	//mov [ecx], eax				;store retval from PRI
    1.97 -	//mov eax, SP_ERROR_NONE		;set no error
    1.98 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
    1.99 -	IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
   1.100 -	IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
   1.101 -
   1.102 -	/* save where error checking/halting functions should go to */
   1.103 -	jitoffs_t offs_return = jit->get_outputpos();
   1.104 -	//mov esp, [esi+NSTACK]			;restore stack pointer
   1.105 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_ESP, REG_ESI, AMX_INFO_NSTACK);
   1.106 -
   1.107 -	/* Restore SP */
   1.108 -	//mov ecx, [esi+CONTEXT]
   1.109 -	//sub edi, ebp
   1.110 -	//mov [ecx+SP], edi
   1.111 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
   1.112 -	IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
   1.113 -	IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
   1.114 -
   1.115 -	//pop ebx
   1.116 -	//pop edi
   1.117 -	//pop esi
   1.118 -	//pop ebp
   1.119 -	//ret
   1.120 -	IA32_Pop_Reg(jit, REG_EBX);
   1.121 -	IA32_Pop_Reg(jit, REG_EDI);
   1.122 -	IA32_Pop_Reg(jit, REG_ESI);
   1.123 -	IA32_Pop_Reg(jit, REG_EBP);
   1.124 -	IA32_Return(jit);
   1.125 -
   1.126 -	return offs_return;
   1.127 -}
   1.128 -
   1.129 -void Write_GetError(JitWriter *jit)
   1.130 -{
   1.131 -	//mov eax, [esi+info.context]
   1.132 -	//mov eax, [eax+ctx.error]
   1.133 -	//jmp [jit_return]
   1.134 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
   1.135 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
   1.136 -	IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
   1.137 -}
   1.138 -
   1.139 -void Write_SetError(JitWriter *jit, int error)
   1.140 -{
   1.141 -	//mov eax, <error>
   1.142 -	//jmp [jit_return]
   1.143 -	IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
   1.144 -	IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
   1.145 -}
   1.146 -
   1.147 -void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
   1.148 -{
   1.149 -	//test reg, reg
   1.150 -	//jz :error
   1.151 -	IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
   1.152 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
   1.153 -}
   1.154 -
   1.155 -void Write_CheckHeap_Min(JitWriter *jit)
   1.156 -{
   1.157 -	/* Check if the stack went beyond the heap low.
   1.158 -	 * This usually means there was a compiler error.
   1.159 -	 * NOTE: Special optimization here.
   1.160 -	 * The heap low is always known ahead of time! :)
   1.161 -	 */
   1.162 -	CompData *data = (CompData *)jit->data;
   1.163 -	//cmp [esi+info.heap], <heaplow>
   1.164 -	//jb :error
   1.165 -	IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
   1.166 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_B, data->jit_error_heapmin);
   1.167 -}
   1.168 -
   1.169 -void Write_CheckHeap_Low(JitWriter *jit)
   1.170 -{
   1.171 -	/* Check if the heap is trying to grow beyond the stack.
   1.172 -	 */
   1.173 -	//mov ecx, [esi+info.heap]
   1.174 -	//lea ecx, [ebp+ecx+STACK_MARGIN]
   1.175 -	//cmp ecx, edi
   1.176 -	//ja :error		; I think this is right
   1.177 -	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
   1.178 -	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
   1.179 -	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
   1.180 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
   1.181 -}
   1.182 -
   1.183 -void Write_CheckStack_Min(JitWriter *jit)
   1.184 -{
   1.185 -	/* Check if the stack went beyond the stack top
   1.186 -	 * This usually means there was a compiler error.
   1.187 -	 */
   1.188 -	//cmp edi, [esi+info.stacktop]
   1.189 -	//jae :error
   1.190 -	IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
   1.191 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
   1.192 -}
   1.193 -
   1.194 -void Write_CheckStack_Low(JitWriter *jit)
   1.195 -{
   1.196 -	/* Check if the stack went beyond the heap boundary.
   1.197 -	 * Unfortunately this one isn't as quick as the other check.
   1.198 -	 * The stack margin check is important for sysreq.n having space.
   1.199 -	 */
   1.200 -	//mov ecx, [esi+info.heap]
   1.201 -	//lea ecx, [ebp+ecx+STACK_MARGIN]
   1.202 -	//cmp edi, ecx
   1.203 -	//jb :error		; I think this is right
   1.204 -	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
   1.205 -	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
   1.206 -	IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
   1.207 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
   1.208 -}
   1.209 -
   1.210 -void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
   1.211 -{
   1.212 -	/* :TODO: Should this be checking for below heaplow?
   1.213 -	 * The old JIT did not.
   1.214 -	 */
   1.215 -
   1.216 -	/** 
   1.217 -	 * :TODO: If we can't find a nicer way of doing this,
   1.218 -	 *  then scrap it on high optimizations.  The second portion is not needed at all!
   1.219 -	 */
   1.220 -
   1.221 -	/* Part 1: Check if we're in the memory bounds */
   1.222 -	//cmp <reg>, <stpu>
   1.223 -	//jae :error
   1.224 -	IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->mem_size);
   1.225 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
   1.226 -
   1.227 -	/* Part 2: Check if we're in the invalid region between HP and SP */
   1.228 -	jitoffs_t jmp;
   1.229 -	//cmp <reg>, [esi+info.heap]
   1.230 -	//jb :continue
   1.231 -	//lea ecx, [ebp+<reg>]
   1.232 -	//cmp edi, ecx
   1.233 -	//jb :error
   1.234 -	//:continue
   1.235 -	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
   1.236 -	jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
   1.237 -	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
   1.238 -	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
   1.239 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
   1.240 -	IA32_Send_Jump8_Here(jit, jmp);
   1.241 -}
   1.242 -
   1.243 -void Macro_PushN_Addr(JitWriter *jit, int i)
   1.244 -{
   1.245 -	//push eax
   1.246 -	//mov eax, [esi+frm]
   1.247 -	//loop i times:
   1.248 -	// lea ecx, [eax+<val>]
   1.249 -	// mov [edi-4*i], ecx
   1.250 -	//sub edi, 4*N
   1.251 -	//pop eax
   1.252 -
   1.253 -	cell_t val;
   1.254 -	int n = 1;
   1.255 -	IA32_Push_Reg(jit, AMX_REG_PRI);
   1.256 -	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
   1.257 -	do
   1.258 -	{
   1.259 -		val = jit->read_cell();
   1.260 -		if (val <= SCHAR_MAX && val >= SCHAR_MIN)
   1.261 -			IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
   1.262 -		else
   1.263 -			IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
   1.264 -		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   1.265 -	} while (n++ < i);
   1.266 -	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   1.267 -	IA32_Pop_Reg(jit, AMX_REG_PRI);
   1.268 -}
   1.269 -
   1.270 -void Macro_PushN_S(JitWriter *jit, int i)
   1.271 -{
   1.272 -	//loop i times:
   1.273 -	// mov ecx, [ebx+<val>]
   1.274 -	// mov [edi-4*i], ecx
   1.275 -	//sub edi, 4*N
   1.276 -
   1.277 -	cell_t val;
   1.278 -	int n = 1;
   1.279 -	do 
   1.280 -	{
   1.281 -		val = jit->read_cell();
   1.282 -		if (val <= SCHAR_MAX && val >= SCHAR_MIN)
   1.283 -			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
   1.284 -		else
   1.285 -			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
   1.286 -		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   1.287 -	} while (n++ < i);
   1.288 -	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   1.289 -}
   1.290 -
   1.291 -void Macro_PushN_C(JitWriter *jit, int i)
   1.292 -{
   1.293 -	//loop i times:
   1.294 -	// mov [edi-4*i], <val>
   1.295 -	//sub edi, 4*N
   1.296 -
   1.297 -	int n = 1;
   1.298 -	do 
   1.299 -	{
   1.300 -		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
   1.301 -	} while (n++ < i);
   1.302 -	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   1.303 -}
   1.304 -
   1.305 -void Macro_PushN(JitWriter *jit, int i)
   1.306 -{
   1.307 -	//loop i times:
   1.308 -	// mov ecx, [ebp+<val>]
   1.309 -	// mov [edi-4*i], ecx
   1.310 -	//sub edi, 4*N
   1.311 -
   1.312 -	cell_t val;
   1.313 -	int n = 1;
   1.314 -	do 
   1.315 -	{
   1.316 -		val = jit->read_cell();
   1.317 -		if (val <= SCHAR_MAX && val >= SCHAR_MIN)
   1.318 -			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
   1.319 -		else
   1.320 -			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
   1.321 -		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
   1.322 -	} while (n++ < i);
   1.323 -	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
   1.324 -}
   1.325 -
   1.326 -void WriteOp_Sysreq_C_Function(JitWriter *jit)
   1.327 -{
   1.328 -	/* The small daddy of the big daddy of opcodes.
   1.329 -	 * ecx - native index
   1.330 -	 */
   1.331 -	CompData *data = (CompData *)jit->data;
   1.332 -
   1.333 -	/* save registers we will need */
   1.334 -	//push edx
   1.335 -	IA32_Push_Reg(jit, AMX_REG_ALT);
   1.336 -
   1.337 -	/* Align the stack to 16 bytes */
   1.338 -	//push ebx
   1.339 -	//mov ebx, esp
   1.340 -	//and esp, 0xFFFFFF0
   1.341 -	//sub esp, 4
   1.342 -	IA32_Push_Reg(jit, REG_EBX);
   1.343 -	IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
   1.344 -	IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
   1.345 -	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
   1.346 -
   1.347 -	/* push some callback stuff */
   1.348 -	//push edi		; stack
   1.349 -	//push ecx		; native index
   1.350 -	IA32_Push_Reg(jit, AMX_REG_STK);
   1.351 -	IA32_Push_Reg(jit, REG_ECX);
   1.352 -
   1.353 -	/* Relocate stack, heap, frm information, then store back */
   1.354 -	//mov eax, [esi+context]
   1.355 -	//mov ecx, [esi+hea]
   1.356 -	//sub edi, ebp
   1.357 -	//mov [eax+hp], ecx
   1.358 -	//mov ecx, [esi]
   1.359 -	//mov [eax+sp], edi
   1.360 -	//mov [eax+frm], ecx
   1.361 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
   1.362 -	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
   1.363 -	IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
   1.364 -	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
   1.365 -	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
   1.366 -	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
   1.367 -	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
   1.368 -
   1.369 -	/* finally, push the last parameter and make the call */
   1.370 -	//push eax		; context
   1.371 -	//call NativeCallback
   1.372 -	IA32_Push_Reg(jit, REG_EAX);
   1.373 -	jitoffs_t call = IA32_Call_Imm32(jit, 0);
   1.374 -	IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
   1.375 -
   1.376 -	/* Test for error */
   1.377 -	//mov ecx, [esi+context]
   1.378 -	//cmp [ecx+err], 0
   1.379 -	//jnz :error
   1.380 -	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
   1.381 -	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
   1.382 -	IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, data->jit_extern_error);
   1.383 -
   1.384 -	/* restore what we damaged */
   1.385 -	//mov esp, ebx
   1.386 -	//pop ebx
   1.387 -	//add edi, ebp
   1.388 -	//pop edx
   1.389 -	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
   1.390 -	IA32_Pop_Reg(jit, REG_EBX);
   1.391 -	IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
   1.392 -	IA32_Pop_Reg(jit, AMX_REG_ALT);
   1.393 -
   1.394 -	//ret
   1.395 -	IA32_Return(jit);
   1.396 -}
   1.397 -
   1.398 -typedef struct array_creation_s
   1.399 -{
   1.400 -	const cell_t *dim_list;				/* Dimension sizes */
   1.401 -	cell_t dim_count;					/* Number of dimensions */
   1.402 -	cell_t *data_offs;					/* Current offset AFTER the indirection vectors (data) */
   1.403 -	cell_t *base;						/* array base */
   1.404 -} array_creation_t;
   1.405 -
   1.406 -cell_t _GenerateArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
   1.407 -{
   1.408 -	cell_t write_offs = cur_offs;
   1.409 -	cell_t *data_offs = ar->data_offs;
   1.410 -
   1.411 -	cur_offs += ar->dim_list[dim];
   1.412 -
   1.413 -	/**
   1.414 -	 * Dimension n-x where x > 2 will have sub-vectors.  
   1.415 -	 * Otherwise, we just need to reference the data section.
   1.416 -	 */
   1.417 -	if (ar->dim_count > 2 && dim < ar->dim_count - 2)
   1.418 -	{
   1.419 -		/**
   1.420 -		 * For each index at this dimension, write offstes to our sub-vectors.
   1.421 -		 * After we write one sub-vector, we generate its sub-vectors recursively.
   1.422 -		 * At the end, we're given the next offset we can use.
   1.423 -		 */
   1.424 -		for (int i = 0; i < ar->dim_list[dim]; i++)
   1.425 -		{
   1.426 -			ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
   1.427 -			write_offs++;
   1.428 -			cur_offs = _GenerateArrayIndirectionVectors(ar, dim + 1, cur_offs);
   1.429 -		}
   1.430 -	} else {
   1.431 -		/**
   1.432 -		 * In this section, there are no sub-vectors, we need to write offsets 
   1.433 -		 * to the data.  This is separate so the data stays in one big chunk.
   1.434 -		 * The data offset will increment by the size of the last dimension, 
   1.435 -		 * because that is where the data is finally computed as. 
   1.436 -		 */
   1.437 -		for (int i = 0; i < ar->dim_list[dim]; i++)
   1.438 -		{
   1.439 -			ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
   1.440 -			write_offs++;
   1.441 -			*data_offs = *data_offs + ar->dim_list[dim + 1];
   1.442 -		}
   1.443 -	}
   1.444 -
   1.445 -	return cur_offs;
   1.446 -}
   1.447 -
   1.448 -static cell_t calc_indirection(const array_creation_t *ar, cell_t dim)
   1.449 -{
   1.450 -	cell_t size = ar->dim_list[dim];
   1.451 -
   1.452 -	if (dim < ar->dim_count - 2)
   1.453 -	{
   1.454 -		size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
   1.455 -	}
   1.456 -
   1.457 -	return size;
   1.458 -}
   1.459 -
   1.460 -void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
   1.461 -{
   1.462 -	array_creation_t ar;
   1.463 -	cell_t data_offs;
   1.464 -
   1.465 -	/* Reverse the dimensions */
   1.466 -	cell_t dim_list[sDIMEN_MAX];
   1.467 -	int cur_dim = 0;
   1.468 -	for (int i = _dimcount - 1; i >= 0; i--)
   1.469 -	{
   1.470 -		dim_list[cur_dim++] = dims[i];
   1.471 -	}
   1.472 -	
   1.473 -	ar.base = arraybase;
   1.474 -	ar.dim_list = dim_list;
   1.475 -	ar.dim_count = _dimcount;
   1.476 -	ar.data_offs = &data_offs;
   1.477 -
   1.478 -	data_offs = calc_indirection(&ar, 0);
   1.479 -
   1.480 -	_GenerateArrayIndirectionVectors(&ar, 0, 0);
   1.481 -}
   1.482 -
   1.483 -/**
   1.484 - * A few notes about this function.
   1.485 - * I was more concerned about efficient use of registers here, rather than 
   1.486 - *  fine-tuned optimization.  The reason is that the code is already complicated,
   1.487 - *  and it is very easy to mess up.
   1.488 - */
   1.489 -void WriteIntrinsic_GenArray(JitWriter *jit)
   1.490 -{
   1.491 -	jitoffs_t err1, err2;
   1.492 -
   1.493 -	/**
   1.494 -	 * save important values
   1.495 -	 */
   1.496 -	//push ebx
   1.497 -	//push eax
   1.498 -	//push edx
   1.499 -	//push ecx				;value is referenced on stack
   1.500 -	IA32_Push_Reg(jit, REG_EBX);
   1.501 -	IA32_Push_Reg(jit, REG_EAX);
   1.502 -	IA32_Push_Reg(jit, REG_EDX);
   1.503 -	IA32_Push_Reg(jit, REG_ECX);
   1.504 -
   1.505 -	/**
   1.506 -	 * Calculate how many cells will be needed.
   1.507 -	 */
   1.508 -	//mov edx, [edi]		;get last dimension's count
   1.509 -	//mov eax, 1			;position at second to last dimension
   1.510 -	//:loop
   1.511 -	//cmp eax, [esp]		;compare to # of params
   1.512 -	//jae :done				;end loop if done
   1.513 -	//mov ecx, [edi+eax*4]	;get dimension size
   1.514 -	//imul edx, ecx			;multiply by size
   1.515 -	//add eax, 1			;increment
   1.516 -	//add edx, ecx			;add size (indirection vector)
   1.517 -	//jmp :loop				;jump back
   1.518 -	//:done
   1.519 -	IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
   1.520 -	IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
   1.521 -	jitoffs_t loop1 = jit->get_outputpos();
   1.522 -	IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
   1.523 -	jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
   1.524 -	IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
   1.525 -	IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
   1.526 -	IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
   1.527 -	IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
   1.528 -	IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
   1.529 -	IA32_Send_Jump8_Here(jit, done1);
   1.530 -
   1.531 -	/* Test if we have heap space for this */
   1.532 -	//mov eax, [esi+info.heap]	;get heap pointer
   1.533 -	//lea eax, [eax+edx*4]		;new heap pointer
   1.534 -	//cmp eax, [esi+info.datasz] ;compare to heap low
   1.535 -	//jbe :error				;die if we hit this (it should always be >)
   1.536 -	//add eax, ebp				;relocate to stack
   1.537 -	//cmp eax, edi				;die if above the stack pointer
   1.538 -	//jae :error
   1.539 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
   1.540 -	IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
   1.541 -	IA32_Cmp_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_DATASIZE);
   1.542 -	err1 = IA32_Jump_Cond_Imm32(jit, CC_BE, 0);
   1.543 -	IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
   1.544 -	IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
   1.545 -	err2 = IA32_Jump_Cond_Imm32(jit, CC_AE, 0);
   1.546 -	
   1.547 -	/* Prepare for indirection iteration */
   1.548 -	//mov eax, [esi+info.heap]	;get heap pointer
   1.549 -	//lea ebx, [eax+edx*4]		;new heap pointer
   1.550 -	//mov [esi+info.heap], ebx	;store back
   1.551 -	//push eax					;save heap pointer - we need it
   1.552 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
   1.553 -	IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
   1.554 -	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
   1.555 -	IA32_Push_Reg(jit, REG_EAX);
   1.556 -
   1.557 -	WriteOp_Tracker_Push_Reg(jit, REG_EDX);
   1.558 -	
   1.559 -	/* This part is too messy to do in straight assembly.
   1.560 -	 * I'm letting the compiler handle it and thus it's in C.
   1.561 -	 */
   1.562 -	//lea ebx, [ebp+eax]		;get base pointer
   1.563 -	//push dword [esp-8]		;push autozero
   1.564 -	//push dword [esp-8]		;push dimension count
   1.565 -	//push edi					;push dim array
   1.566 -	//push ebx
   1.567 -	//call GenerateArrayIndirectionVectors
   1.568 -	//add esp, 4*4
   1.569 -	IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
   1.570 -	IA32_Push_Rm_Disp8_ESP(jit, 8);
   1.571 -	IA32_Push_Rm_Disp8_ESP(jit, 8);
   1.572 -	IA32_Push_Reg(jit, REG_EDI);
   1.573 -	IA32_Push_Reg(jit, REG_EBX);
   1.574 -	IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
   1.575 -	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
   1.576 -
   1.577 -	/* Store the heap pointer back into the stack */
   1.578 -	//pop eax					;restore heap pointer
   1.579 -	//pop ecx					;restore param count
   1.580 -	//lea edi, [edi+ecx*4-4]	;pop params-4 off the stack
   1.581 -	//mov [edi], eax			;store back the heap pointer
   1.582 -	IA32_Pop_Reg(jit, REG_EAX);
   1.583 -	IA32_Pop_Reg(jit, REG_ECX);
   1.584 -	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
   1.585 -	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
   1.586 -
   1.587 -	/* Return to caller */
   1.588 -	//pop edx
   1.589 -	//pop eax
   1.590 -	//pop ebx
   1.591 -	//ret
   1.592 -	IA32_Pop_Reg(jit, REG_ECX);
   1.593 -	IA32_Pop_Reg(jit, REG_EAX);
   1.594 -	IA32_Pop_Reg(jit, REG_EBX);
   1.595 -	IA32_Return(jit);
   1.596 -
   1.597 -	//:error
   1.598 -	IA32_Send_Jump32_Here(jit, err1);
   1.599 -	IA32_Send_Jump32_Here(jit, err2);
   1.600 -	Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG);
   1.601 -}
   1.602 -
   1.603 -void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
   1.604 -{
   1.605 -	/* Save registers that may be damaged by the call */
   1.606 -	//push eax
   1.607 -	//push ecx
   1.608 -	//push edi
   1.609 -	//lea edi, [<reg>*4]		; we want the count in bytes not in cells
   1.610 -	IA32_Push_Reg(jit, AMX_REG_PRI);
   1.611 -	if (reg == REG_ECX)
   1.612 -	{
   1.613 -		IA32_Push_Reg(jit, AMX_REG_TMP);
   1.614 -	}
   1.615 -	IA32_Push_Reg(jit, AMX_REG_STK);
   1.616 -	IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
   1.617 -
   1.618 -	/* Get the context ptr, push it and call the check */
   1.619 -	//mov eax, [esi+context]
   1.620 -	//push eax
   1.621 -	//call JIT_VerifyOrAllocateTracker
   1.622 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
   1.623 -	IA32_Push_Reg(jit, REG_EAX);
   1.624 -	jitoffs_t call = IA32_Call_Imm32(jit, 0);
   1.625 -	IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
   1.626 -
   1.627 -	/* Check for errors */
   1.628 -	//cmp eax, 0
   1.629 -	//jnz :error
   1.630 -	IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
   1.631 -	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
   1.632 -
   1.633 -	/* Restore */
   1.634 -	//pop eax
   1.635 -	IA32_Pop_Reg(jit, REG_EAX);
   1.636 -	
   1.637 -	/* Push the register into the stack and increment pCur */
   1.638 -	//mov edx, [eax+vm[]]
   1.639 -	//mov eax, [edx+pcur]
   1.640 -	//add [edx+pcur], 4
   1.641 -	//mov [eax], edi
   1.642 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
   1.643 -	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
   1.644 -	IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
   1.645 -	IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
   1.646 -
   1.647 -	/* Restore PRI, ALT and STK */
   1.648 -	//pop edi
   1.649 -	//pop ecx
   1.650 -	//pop eax
   1.651 -	IA32_Pop_Reg(jit, AMX_REG_STK);
   1.652 -	if (reg == REG_ECX)
   1.653 -	{
   1.654 -		IA32_Pop_Reg(jit, AMX_REG_TMP);
   1.655 -	}
   1.656 -	IA32_Pop_Reg(jit, AMX_REG_PRI);
   1.657 -}
   1.658 -
   1.659 -int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
   1.660 -{
   1.661 -	tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
   1.662 -
   1.663 -	if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
   1.664 -	{
   1.665 -		return SP_ERROR_TRACKER_BOUNDS;
   1.666 -	}
   1.667 -
   1.668 -	if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
   1.669 -	{
   1.670 -		size_t disp = trk->size - 1;
   1.671 -		trk->size *= 2;
   1.672 -		trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
   1.673 -
   1.674 -		if (!trk->pBase)
   1.675 -		{
   1.676 -			return SP_ERROR_TRACKER_BOUNDS;
   1.677 -		}
   1.678 -
   1.679 -		trk->pCur = trk->pBase + disp;
   1.680 -	}
   1.681 -
   1.682 -	return SP_ERROR_NONE;
   1.683 -}
   1.684 -
   1.685 -int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
   1.686 -{
   1.687 -	tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
   1.688 -
   1.689 -	if (trk->pCur <= trk->pBase)
   1.690 -	{
   1.691 -		return SP_ERROR_TRACKER_BOUNDS;
   1.692 -	}
   1.693 -
   1.694 -	return SP_ERROR_NONE;
   1.695 -}
   1.696 -
   1.697 -void AlignMe(JitWriter *jit)
   1.698 -{
   1.699 -	jitoffs_t cur_offs = jit->get_outputpos();
   1.700 -	jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
   1.701 -
   1.702 -	if (offset)
   1.703 -	{
   1.704 -		for (jit_uint32_t i=0; i<offset; i++)
   1.705 -		{
   1.706 -			jit->write_ubyte(IA32_INT3);
   1.707 -		}
   1.708 -	}
   1.709 -}