1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/sourcepawn/jit/x86/opcode_helpers.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,893 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourcePawn JIT
1.8 + * Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This file is not open source and may not be copied without explicit wriiten
1.12 + * permission of AlliedModders LLC. This file may not be redistributed in whole
1.13 + * or significant part.
1.14 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.15 + *
1.16 + * Version: $Id$
1.17 + */
1.18 +
1.19 +#include <limits.h>
1.20 +#include <string.h>
1.21 +#include <malloc.h>
1.22 +#include "jit_x86.h"
1.23 +#include "opcode_helpers.h"
1.24 +#include "x86_macros.h"
1.25 +
1.26 +#define NUM_INFO_PARAMS 5
1.27 +
1.28 +jitoffs_t Write_Execute_Function(JitWriter *jit)
1.29 +{
1.30 + /**
1.31 + * The variables we're passed in:
1.32 + * sp_context_t *ctx, uint32_t code_idx, cell_t *result
1.33 + */
1.34 +
1.35 + /**
1.36 + * !NOTE!
1.37 + * Currently, we do not accept ctx->frm as the new frame pointer.
1.38 + * Instead, we copy the frame from the stack pointer.
1.39 + * This is because we do not support resuming or sleeping!
1.40 + */
1.41 +
1.42 + //push ebp
1.43 + //mov ebp, esp
1.44 + IA32_Push_Reg(jit, REG_EBP);
1.45 + IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
1.46 +
1.47 + //push esi
1.48 + //push edi
1.49 + //push ebx
1.50 + IA32_Push_Reg(jit, REG_ESI);
1.51 + IA32_Push_Reg(jit, REG_EDI);
1.52 + IA32_Push_Reg(jit, REG_EBX);
1.53 +
1.54 + //sub esp, 4*n - reserve info array
1.55 + //mov esi, esp - save info pointer
1.56 + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
1.57 + IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
1.58 +
1.59 + /* Initial memory setup */
1.60 + //mov eax, [ebp+16] - get result pointer
1.61 + //mov [esi+8], eax - store into info pointer
1.62 + //mov eax, [ebp+8] - get context
1.63 + //mov [esi+12], eax - store context into info pointer
1.64 + //mov ecx, [eax+<offs>] - get heap pointer
1.65 + //mov [esi+4], ecx - store heap into info pointer
1.66 + //mov ebp, [eax+<offs>] - get data pointer
1.67 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
1.68 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
1.69 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
1.70 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
1.71 + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
1.72 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
1.73 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory));
1.74 +
1.75 + /* Frame setup */
1.76 + //mov edi, [eax+<offs>] - get stack pointer
1.77 + //add edi, ebp - relocate to data section
1.78 + //mov ebx, edi - copy sp to frm
1.79 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
1.80 + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.81 + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
1.82 +
1.83 + /* Info memory setup */
1.84 + //mov ecx, [eax+<offs>] - copy memsize to temp var
1.85 + //add ecx, ebp - relocate
1.86 + //mov [esi+x], ecx - store relocated
1.87 + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, mem_size));
1.88 + IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
1.89 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
1.90 +
1.91 + /* Remaining needed vars */
1.92 + //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
1.93 + //add ecx, [eax+<offs>] - add code base to index
1.94 + IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
1.95 + IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
1.96 +
1.97 + /* by now, everything is set up, so we can call into the plugin */
1.98 + //call ecx
1.99 + IA32_Call_Reg(jit, REG_ECX);
1.100 +
1.101 + /* if the code flow gets to here, there was a normal return */
1.102 + //mov ecx, [esi+8] - get retval pointer
1.103 + //mov [ecx], eax - store retval from PRI
1.104 + //mov eax, SP_ERROR_NONE - set no error
1.105 + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
1.106 + IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
1.107 + IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
1.108 +
1.109 + /* save where error checking/halting functions should go to */
1.110 + jitoffs_t offs_return = jit->get_outputpos();
1.111 + //mov esp, esi - restore stack pointer
1.112 + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
1.113 +
1.114 + /* _FOR NOW_ ...
1.115 + * We are going to restore SP, HP, and FRM for now. This is for
1.116 + * debugging only, to check for alignment errors. As such:
1.117 + * :TODO: probably remove this.
1.118 + */
1.119 + //mov ecx, [esi+context]
1.120 + //sub edi, ebp
1.121 + //mov edx, [esi+heap]
1.122 + //mov [ecx+sp], edi
1.123 + //mov [ecx+hp], edx
1.124 + IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
1.125 + IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
1.126 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
1.127 + IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
1.128 + IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
1.129 +
1.130 + //add esp, 4*NUM_INFO_PARAMS
1.131 + //pop ebx
1.132 + //pop edi
1.133 + //pop esi
1.134 + //pop ebp
1.135 + //ret
1.136 + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
1.137 + IA32_Pop_Reg(jit, REG_EBX);
1.138 + IA32_Pop_Reg(jit, REG_EDI);
1.139 + IA32_Pop_Reg(jit, REG_ESI);
1.140 + IA32_Pop_Reg(jit, REG_EBP);
1.141 + IA32_Return(jit);
1.142 +
1.143 + return offs_return;
1.144 +}
1.145 +
1.146 +void Write_BreakDebug(JitWriter *jit)
1.147 +{
1.148 + //push edi
1.149 + //mov edi, ecx
1.150 + //mov ecx, [esi+ctx]
1.151 + //cmp [ecx+dbreak], 0
1.152 + //jnz :nocall
1.153 + IA32_Push_Reg(jit, REG_EDI);
1.154 + IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
1.155 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.156 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
1.157 + jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
1.158 +
1.159 + //:TODO: align the stack to 16bytes like in sysreq.x
1.160 + /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
1.161 + //pushad
1.162 + //push [esi+frm]
1.163 + //push ctx
1.164 + //mov ecx, [ecx+dbreak]
1.165 + //call ecx
1.166 + //add esp, 8
1.167 + //popad
1.168 + IA32_Pushad(jit);
1.169 + IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
1.170 + IA32_Push_Reg(jit, AMX_REG_TMP);
1.171 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
1.172 + IA32_Call_Reg(jit, AMX_REG_TMP);
1.173 + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
1.174 + IA32_Popad(jit);
1.175 +
1.176 + //:nocall
1.177 + //pop edi
1.178 + //ret
1.179 + IA32_Pop_Reg(jit, REG_EDI);
1.180 + IA32_Send_Jump8_Here(jit, jmp);
1.181 + IA32_Return(jit);
1.182 +}
1.183 +
1.184 +void Write_GetError(JitWriter *jit)
1.185 +{
1.186 + CompData *data = (CompData *)jit->data;
1.187 +
1.188 + //mov eax, [esi+info.context]
1.189 + //mov eax, [eax+ctx.error]
1.190 + //jmp [jit_return]
1.191 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.192 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
1.193 + IA32_Jump_Imm32_Abs(jit, data->jit_return);
1.194 +}
1.195 +
1.196 +void Write_SetError(JitWriter *jit, int error)
1.197 +{
1.198 + CompData *data = (CompData *)jit->data;
1.199 +
1.200 + //mov eax, <error>
1.201 + //jmp [jit_return]
1.202 + IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
1.203 + IA32_Jump_Imm32_Abs(jit, data->jit_return);
1.204 +}
1.205 +
1.206 +void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
1.207 +{
1.208 + //test reg, reg
1.209 + //jz :error
1.210 + IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
1.211 + IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
1.212 +}
1.213 +
1.214 +void Write_CheckHeap_Min(JitWriter *jit)
1.215 +{
1.216 + /* Check if the stack went beyond the heap low.
1.217 + * This usually means there was a compiler error.
1.218 + * NOTE: Special optimization here.
1.219 + * The heap low is always known ahead of time! :)
1.220 + */
1.221 + CompData *data = (CompData *)jit->data;
1.222 + //cmp [esi+info.heap], <heaplow>
1.223 + //jb :error
1.224 + IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
1.225 + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
1.226 +}
1.227 +
1.228 +void Write_CheckHeap_Low(JitWriter *jit)
1.229 +{
1.230 + /* Check if the heap is trying to grow beyond the stack.
1.231 + */
1.232 + //mov ecx, [esi+info.heap]
1.233 + //lea ecx, [ebp+ecx+STACK_MARGIN]
1.234 + //cmp ecx, edi
1.235 + //ja :error ; I think this is right
1.236 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
1.237 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
1.238 + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
1.239 + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
1.240 +}
1.241 +
1.242 +void Write_CheckStack_Min(JitWriter *jit)
1.243 +{
1.244 + /* Check if the stack went beyond the stack top
1.245 + * This usually means there was a compiler error.
1.246 + */
1.247 + //cmp edi, [esi+info.stacktop]
1.248 + //jae :error
1.249 + IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
1.250 + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
1.251 +}
1.252 +
1.253 +void Write_CheckStack_Low(JitWriter *jit)
1.254 +{
1.255 + /* Check if the stack went beyond the heap boundary.
1.256 + * Unfortunately this one isn't as quick as the other check.
1.257 + * The stack margin check is important for sysreq.n having space.
1.258 + */
1.259 + //mov ecx, [esi+info.heap]
1.260 + //lea ecx, [ebp+ecx+STACK_MARGIN]
1.261 + //cmp edi, ecx
1.262 + //jb :error ; I think this is right
1.263 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
1.264 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
1.265 + IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
1.266 + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
1.267 +}
1.268 +
1.269 +void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
1.270 +{
1.271 + CompData *data = (CompData *)jit->data;
1.272 +
1.273 + /* :TODO: Should this be checking for below heaplow?
1.274 + * The old JIT did not.
1.275 + */
1.276 +
1.277 + bool call = false;
1.278 + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
1.279 + {
1.280 + /* If we're not in the initial generation phase,
1.281 + * Write a call to the actual routine instead.
1.282 + */
1.283 + if ((reg == REG_EAX) && data->jit_verify_addr_eax)
1.284 + {
1.285 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.286 + IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
1.287 + return;
1.288 + } else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
1.289 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.290 + IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
1.291 + return;
1.292 + }
1.293 + call = true;
1.294 + }
1.295 +
1.296 + /**
1.297 + * :TODO: If we can't find a nicer way of doing this,
1.298 + * then scrap it on high optimizations. The second portion is not needed at all!
1.299 + */
1.300 +
1.301 + /* Part 1: Check if we're in the memory bounds */
1.302 + //cmp <reg>, <stpu>
1.303 + //jae :error
1.304 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
1.305 + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
1.306 +
1.307 + /* Part 2: Check if we're in the invalid region between HP and SP */
1.308 + jitoffs_t jmp;
1.309 + //cmp <reg>, [esi+info.heap]
1.310 + //jb :continue
1.311 + //lea ecx, [ebp+<reg>]
1.312 + //cmp edi, ecx
1.313 + //jb :error
1.314 + //:continue
1.315 + IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
1.316 + jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
1.317 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
1.318 + IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
1.319 + IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
1.320 + IA32_Send_Jump8_Here(jit, jmp);
1.321 +
1.322 + if (call)
1.323 + {
1.324 + IA32_Return(jit);
1.325 + }
1.326 +}
1.327 +
1.328 +void Macro_PushN_Addr(JitWriter *jit, int i)
1.329 +{
1.330 + //push eax
1.331 + //mov eax, [esi+frm]
1.332 + //loop i times:
1.333 + // lea ecx, [eax+<val>]
1.334 + // mov [edi-4*i], ecx
1.335 + //sub edi, 4*N
1.336 + //pop eax
1.337 +
1.338 + cell_t val;
1.339 + int n = 1;
1.340 + IA32_Push_Reg(jit, AMX_REG_PRI);
1.341 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
1.342 + do
1.343 + {
1.344 + val = jit->read_cell();
1.345 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.346 + IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
1.347 + else
1.348 + IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
1.349 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
1.350 + } while (n++ < i);
1.351 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
1.352 + IA32_Pop_Reg(jit, AMX_REG_PRI);
1.353 +}
1.354 +
1.355 +void Macro_PushN_S(JitWriter *jit, int i)
1.356 +{
1.357 + //loop i times:
1.358 + // mov ecx, [ebx+<val>]
1.359 + // mov [edi-4*i], ecx
1.360 + //sub edi, 4*N
1.361 +
1.362 + cell_t val;
1.363 + int n = 1;
1.364 + do
1.365 + {
1.366 + val = jit->read_cell();
1.367 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.368 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
1.369 + else
1.370 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
1.371 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
1.372 + } while (n++ < i);
1.373 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
1.374 +}
1.375 +
1.376 +void Macro_PushN_C(JitWriter *jit, int i)
1.377 +{
1.378 + //loop i times:
1.379 + // mov [edi-4*i], <val>
1.380 + //sub edi, 4*N
1.381 +
1.382 + int n = 1;
1.383 + do
1.384 + {
1.385 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
1.386 + } while (n++ < i);
1.387 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
1.388 +}
1.389 +
1.390 +void Macro_PushN(JitWriter *jit, int i)
1.391 +{
1.392 + //loop i times:
1.393 + // mov ecx, [ebp+<val>]
1.394 + // mov [edi-4*i], ecx
1.395 + //sub edi, 4*N
1.396 +
1.397 + cell_t val;
1.398 + int n = 1;
1.399 + do
1.400 + {
1.401 + val = jit->read_cell();
1.402 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.403 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
1.404 + else
1.405 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
1.406 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
1.407 + } while (n++ < i);
1.408 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
1.409 +}
1.410 +
1.411 +void WriteOp_Sysreq_C_Function(JitWriter *jit)
1.412 +{
1.413 + /* The small daddy of the big daddy of opcodes.
1.414 + * ecx - native index
1.415 + */
1.416 + CompData *data = (CompData *)jit->data;
1.417 +
1.418 + /* save registers we will need */
1.419 + //push edx
1.420 + IA32_Push_Reg(jit, AMX_REG_ALT);
1.421 +
1.422 + /* Align the stack to 16 bytes */
1.423 + //push ebx
1.424 + //mov ebx, esp
1.425 + //and esp, 0xFFFFFF0
1.426 + //sub esp, 4
1.427 + IA32_Push_Reg(jit, REG_EBX);
1.428 + IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
1.429 + IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
1.430 + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
1.431 +
1.432 + /* push some callback stuff */
1.433 + //push edi ; stack
1.434 + //push ecx ; native index
1.435 + IA32_Push_Reg(jit, AMX_REG_STK);
1.436 + IA32_Push_Reg(jit, REG_ECX);
1.437 +
1.438 + /* Relocate stack, heap, frm information, then store back */
1.439 + //mov eax, [esi+context]
1.440 + //mov ecx, [esi+hea]
1.441 + //sub edi, ebp
1.442 + //mov [eax+hp], ecx
1.443 + //mov ecx, [esi]
1.444 + //mov [eax+sp], edi
1.445 + //mov [eax+frm], ecx
1.446 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.447 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
1.448 + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.449 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
1.450 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
1.451 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
1.452 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
1.453 +
1.454 + /* finally, push the last parameter and make the call */
1.455 + //push eax ; context
1.456 + //call NativeCallback
1.457 + IA32_Push_Reg(jit, REG_EAX);
1.458 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.459 + if (!data->debug)
1.460 + {
1.461 + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
1.462 + } else {
1.463 + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
1.464 + }
1.465 +
1.466 + /* Test for error */
1.467 + //mov ecx, [esi+context]
1.468 + //cmp [ecx+err], 0
1.469 + //jnz :error
1.470 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.471 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
1.472 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
1.473 +
1.474 + /* restore what we damaged */
1.475 + //mov esp, ebx
1.476 + //pop ebx
1.477 + //add edi, ebp
1.478 + //pop edx
1.479 + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
1.480 + IA32_Pop_Reg(jit, REG_EBX);
1.481 + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.482 + IA32_Pop_Reg(jit, AMX_REG_ALT);
1.483 +
1.484 + //ret
1.485 + IA32_Return(jit);
1.486 +}
1.487 +
1.488 +typedef struct array_creation_s
1.489 +{
1.490 + const cell_t *dim_list; /* Dimension sizes */
1.491 + cell_t dim_count; /* Number of dimensions */
1.492 + cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
1.493 + cell_t *base; /* array base */
1.494 +} array_creation_t;
1.495 +
1.496 +cell_t _GenerateArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
1.497 +{
1.498 + cell_t write_offs = cur_offs;
1.499 + cell_t *data_offs = ar->data_offs;
1.500 +
1.501 + cur_offs += ar->dim_list[dim];
1.502 +
1.503 + /**
1.504 + * Dimension n-x where x > 2 will have sub-vectors.
1.505 + * Otherwise, we just need to reference the data section.
1.506 + */
1.507 + if (ar->dim_count > 2 && dim < ar->dim_count - 2)
1.508 + {
1.509 + /**
1.510 + * For each index at this dimension, write offstes to our sub-vectors.
1.511 + * After we write one sub-vector, we generate its sub-vectors recursively.
1.512 + * At the end, we're given the next offset we can use.
1.513 + */
1.514 + for (int i = 0; i < ar->dim_list[dim]; i++)
1.515 + {
1.516 + ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
1.517 + write_offs++;
1.518 + cur_offs = _GenerateArrayIndirectionVectors(ar, dim + 1, cur_offs);
1.519 + }
1.520 + } else {
1.521 + /**
1.522 + * In this section, there are no sub-vectors, we need to write offsets
1.523 + * to the data. This is separate so the data stays in one big chunk.
1.524 + * The data offset will increment by the size of the last dimension,
1.525 + * because that is where the data is finally computed as.
1.526 + */
1.527 + for (int i = 0; i < ar->dim_list[dim]; i++)
1.528 + {
1.529 + ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
1.530 + write_offs++;
1.531 + *data_offs = *data_offs + ar->dim_list[dim + 1];
1.532 + }
1.533 + }
1.534 +
1.535 + return cur_offs;
1.536 +}
1.537 +
1.538 +static cell_t calc_indirection(const array_creation_t *ar, cell_t dim)
1.539 +{
1.540 + cell_t size = ar->dim_list[dim];
1.541 +
1.542 + if (dim < ar->dim_count - 2)
1.543 + {
1.544 + size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
1.545 + }
1.546 +
1.547 + return size;
1.548 +}
1.549 +
1.550 +void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
1.551 +{
1.552 + array_creation_t ar;
1.553 + cell_t data_offs;
1.554 +
1.555 + /* Reverse the dimensions */
1.556 + cell_t dim_list[sDIMEN_MAX];
1.557 + int cur_dim = 0;
1.558 + for (int i = _dimcount - 1; i >= 0; i--)
1.559 + {
1.560 + dim_list[cur_dim++] = dims[i];
1.561 + }
1.562 +
1.563 + ar.base = arraybase;
1.564 + ar.dim_list = dim_list;
1.565 + ar.dim_count = _dimcount;
1.566 + ar.data_offs = &data_offs;
1.567 +
1.568 + data_offs = calc_indirection(&ar, 0);
1.569 +
1.570 + _GenerateArrayIndirectionVectors(&ar, 0, 0);
1.571 +}
1.572 +
1.573 +/**
1.574 + * A few notes about this function.
1.575 + * I was more concerned about efficient use of registers here, rather than
1.576 + * fine-tuned optimization. The reason is that the code is already complicated,
1.577 + * and it is very easy to mess up.
1.578 + */
1.579 +void WriteIntrinsic_GenArray(JitWriter *jit)
1.580 +{
1.581 + /**
1.582 + * save important values
1.583 + */
1.584 + //push ebx
1.585 + //push eax
1.586 + //push edx
1.587 + //push ecx ;value is referenced on stack
1.588 + IA32_Push_Reg(jit, REG_EBX);
1.589 + IA32_Push_Reg(jit, REG_EAX);
1.590 + IA32_Push_Reg(jit, REG_EDX);
1.591 + IA32_Push_Reg(jit, REG_ECX);
1.592 +
1.593 + /**
1.594 + * Calculate how many cells will be needed.
1.595 + */
1.596 + //mov edx, [edi] ;get last dimension's count
1.597 + //mov eax, 1 ;position at second to last dimension
1.598 + //:loop
1.599 + //cmp eax, [esp] ;compare to # of params
1.600 + //jae :done ;end loop if done
1.601 + //mov ecx, [edi+eax*4] ;get dimension size
1.602 + //imul edx, ecx ;multiply by size
1.603 + //add eax, 1 ;increment
1.604 + //add edx, ecx ;add size (indirection vector)
1.605 + //jmp :loop ;jump back
1.606 + //:done
1.607 + IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
1.608 + IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
1.609 + jitoffs_t loop1 = jit->get_outputpos();
1.610 + IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
1.611 + jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
1.612 + IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
1.613 + IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
1.614 + IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
1.615 + IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
1.616 + IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
1.617 + IA32_Send_Jump8_Here(jit, done1);
1.618 +
1.619 + /* Test if we have heap space for this */
1.620 + //mov eax, [esi+info.heap] ;get heap pointer
1.621 + //lea eax, [eax+edx*4] ;new heap pointer
1.622 + //cmp eax, <hlw> ;compare to heap low
1.623 + //jbe :error ;die if we hit this (it should always be >)
1.624 + //add eax, ebp ;relocate to stack
1.625 + //cmp eax, edi ;die if above the stack pointer
1.626 + //jae :error
1.627 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
1.628 + IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
1.629 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
1.630 + IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
1.631 + IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
1.632 + IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
1.633 + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
1.634 +
1.635 + /* Prepare for indirection iteration */
1.636 + //mov eax, [esi+info.heap] ;get heap pointer
1.637 + //lea ebx, [eax+edx*4] ;new heap pointer
1.638 + //mov [esi+info.heap], ebx ;store back
1.639 + //push eax ;save heap pointer - we need it
1.640 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
1.641 + IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
1.642 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
1.643 + IA32_Push_Reg(jit, REG_EAX);
1.644 +
1.645 + WriteOp_Tracker_Push_Reg(jit, REG_EDX);
1.646 +
1.647 + /* This part is too messy to do in straight assembly.
1.648 + * I'm letting the compiler handle it and thus it's in C.
1.649 + */
1.650 + //lea ebx, [ebp+eax] ;get base pointer
1.651 + //push dword [esp-8] ;push autozero
1.652 + //push dword [esp-8] ;push dimension count
1.653 + //push edi ;push dim array
1.654 + //push ebx
1.655 + //call GenerateArrayIndirectionVectors
1.656 + //add esp, 4*4
1.657 + IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
1.658 + IA32_Push_Rm_Disp8_ESP(jit, 8);
1.659 + IA32_Push_Rm_Disp8_ESP(jit, 8);
1.660 + IA32_Push_Reg(jit, REG_EDI);
1.661 + IA32_Push_Reg(jit, REG_EBX);
1.662 + IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
1.663 + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
1.664 +
1.665 + /* Store the heap pointer back into the stack */
1.666 + //pop eax ;restore heap pointer
1.667 + //pop ecx ;restore param count
1.668 + //lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
1.669 + //mov [edi], eax ;store back the heap pointer
1.670 + IA32_Pop_Reg(jit, REG_EAX);
1.671 + IA32_Pop_Reg(jit, REG_ECX);
1.672 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
1.673 + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
1.674 +
1.675 + /* Return to caller */
1.676 + //pop edx
1.677 + //pop eax
1.678 + //pop ebx
1.679 + //ret
1.680 + IA32_Pop_Reg(jit, REG_ECX);
1.681 + IA32_Pop_Reg(jit, REG_EAX);
1.682 + IA32_Pop_Reg(jit, REG_EBX);
1.683 + IA32_Return(jit);
1.684 +}
1.685 +
1.686 +void WriteOp_Sysreq_N_Function(JitWriter *jit)
1.687 +{
1.688 + /* The big daddy of opcodes.
1.689 + * eax - num_params
1.690 + * ecx - native index
1.691 + */
1.692 + CompData *data = (CompData *)jit->data;
1.693 +
1.694 + /* store the number of parameters on the stack */
1.695 + //mov [edi-4], eax
1.696 + //sub edi, 4
1.697 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
1.698 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.699 +
1.700 + /* save registers we will need */
1.701 + //push eax ; num_params for stack popping
1.702 + //push edx
1.703 + IA32_Push_Reg(jit, REG_EAX);
1.704 + IA32_Push_Reg(jit, AMX_REG_ALT);
1.705 +
1.706 + /* Align the stack to 16 bytes */
1.707 + //push ebx
1.708 + //mov ebx, esp
1.709 + //and esp, 0xFFFFFF0
1.710 + //sub esp, 4
1.711 + IA32_Push_Reg(jit, REG_EBX);
1.712 + IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
1.713 + IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
1.714 + IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
1.715 +
1.716 + /* push some callback stuff */
1.717 + //push edi ; stack
1.718 + //push ecx ; native index
1.719 + IA32_Push_Reg(jit, AMX_REG_STK);
1.720 + IA32_Push_Reg(jit, REG_ECX);
1.721 +
1.722 + /* Relocate stack, heap, frm information, then store back */
1.723 + //mov eax, [esi+context]
1.724 + //mov ecx, [esi+hea]
1.725 + //sub edi, ebp
1.726 + //mov [eax+hp], ecx
1.727 + //mov ecx, [esi]
1.728 + //mov [eax+sp], edi
1.729 + //mov [eax+frm], ecx
1.730 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.731 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
1.732 + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.733 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
1.734 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
1.735 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
1.736 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
1.737 +
1.738 + /* finally, push the last parameter and make the call */
1.739 + //push eax ; context
1.740 + //call NativeCallback
1.741 + IA32_Push_Reg(jit, REG_EAX);
1.742 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.743 + if (!data->debug)
1.744 + {
1.745 + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
1.746 + } else {
1.747 + IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
1.748 + }
1.749 +
1.750 + /* Test for error */
1.751 + //mov ecx, [esi+context]
1.752 + //cmp [ecx+err], 0
1.753 + //jnz :error
1.754 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.755 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
1.756 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
1.757 +
1.758 + /* restore what we damaged */
1.759 + //mov esp, ebx
1.760 + //pop ebx
1.761 + //add edi, ebp
1.762 + //pop edx
1.763 + //pop ecx ; num_params
1.764 + IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
1.765 + IA32_Pop_Reg(jit, REG_EBX);
1.766 + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.767 + IA32_Pop_Reg(jit, AMX_REG_ALT);
1.768 + IA32_Pop_Reg(jit, REG_ECX);
1.769 +
1.770 + /* pop the AMX stack. do not check the margins.
1.771 + * Note that this is not a true macro - we don't bother to
1.772 + * set ALT here because nothing will be using it.
1.773 + */
1.774 + //lea edi, [edi+ecx*4+4]
1.775 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
1.776 +
1.777 + //ret
1.778 + IA32_Return(jit);
1.779 +}
1.780 +
1.781 +void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
1.782 +{
1.783 + CompData *data = (CompData *)jit->data;
1.784 +
1.785 + /* Save registers that may be damaged by the call */
1.786 + //push eax
1.787 + //push ecx
1.788 + //push edi
1.789 + //lea edi, [<reg>*4] ; we want the count in bytes not in cells
1.790 + IA32_Push_Reg(jit, AMX_REG_PRI);
1.791 + if (reg == REG_ECX)
1.792 + {
1.793 + IA32_Push_Reg(jit, AMX_REG_TMP);
1.794 + }
1.795 + IA32_Push_Reg(jit, AMX_REG_STK);
1.796 + IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
1.797 +
1.798 + /* Get the context ptr, push it and call the check */
1.799 + //mov eax, [esi+context]
1.800 + //push eax
1.801 + //call JIT_VerifyOrAllocateTracker
1.802 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.803 + IA32_Push_Reg(jit, REG_EAX);
1.804 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.805 + IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
1.806 +
1.807 + /* Check for errors */
1.808 + //cmp eax, 0
1.809 + //jnz :error
1.810 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
1.811 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
1.812 +
1.813 + /* Restore */
1.814 + //pop eax
1.815 + IA32_Pop_Reg(jit, REG_EAX);
1.816 +
1.817 + /* Push the register into the stack and increment pCur */
1.818 + //mov edx, [eax+vm[]]
1.819 + //mov eax, [edx+pcur]
1.820 + //add [edx+pcur], 4
1.821 + //mov [eax], edi
1.822 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
1.823 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
1.824 + IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
1.825 + IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
1.826 +
1.827 + /* Restore PRI, ALT and STK */
1.828 + //pop edi
1.829 + //pop ecx
1.830 + //pop eax
1.831 + IA32_Pop_Reg(jit, AMX_REG_STK);
1.832 + if (reg == REG_ECX)
1.833 + {
1.834 + IA32_Pop_Reg(jit, AMX_REG_TMP);
1.835 + }
1.836 + IA32_Pop_Reg(jit, AMX_REG_PRI);
1.837 +}
1.838 +
1.839 +int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
1.840 +{
1.841 + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
1.842 +
1.843 + if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
1.844 + {
1.845 + return SP_ERROR_TRACKER_BOUNDS;
1.846 + }
1.847 +
1.848 + if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
1.849 + {
1.850 + size_t disp = trk->size - 1;
1.851 + trk->size *= 2;
1.852 + trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
1.853 +
1.854 + if (!trk->pBase)
1.855 + {
1.856 + return SP_ERROR_TRACKER_BOUNDS;
1.857 + }
1.858 +
1.859 + trk->pCur = trk->pBase + disp;
1.860 + }
1.861 +
1.862 + return SP_ERROR_NONE;
1.863 +}
1.864 +
1.865 +int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
1.866 +{
1.867 + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
1.868 +
1.869 + if (trk->pCur <= trk->pBase)
1.870 + {
1.871 + return SP_ERROR_TRACKER_BOUNDS;
1.872 + }
1.873 +
1.874 + return SP_ERROR_NONE;
1.875 +}
1.876 +
1.877 +void Write_RoundingTable(JitWriter *jit)
1.878 +{
1.879 + jit->write_int32(-1);
1.880 + jit->write_int32(0);
1.881 + jit->write_int32(1);
1.882 +}
1.883 +
1.884 +void AlignMe(JitWriter *jit)
1.885 +{
1.886 + jitoffs_t cur_offs = jit->get_outputpos();
1.887 + jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
1.888 +
1.889 + if (offset)
1.890 + {
1.891 + for (jit_uint32_t i=0; i<offset; i++)
1.892 + {
1.893 + jit->write_ubyte(IA32_INT3);
1.894 + }
1.895 + }
1.896 +}