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 -}