1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp Wed Nov 08 06:24:28 2006 +0000
1.3 @@ -0,0 +1,2165 @@
1.4 +#include <string.h>
1.5 +#include <stdlib.h>
1.6 +#include <assert.h>
1.7 +#include "jit_x86.h"
1.8 +#include "opcode_helpers.h"
1.9 +#include "x86_macros.h"
1.10 +
1.11 +#if defined USE_UNGEN_OPCODES
1.12 +#include "ungen_opcodes.h"
1.13 +#endif
1.14 +
1.15 +inline void WriteOp_Move_Pri(JitWriter *jit)
1.16 +{
1.17 + //mov eax, edx
1.18 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.19 +}
1.20 +
1.21 +inline void WriteOp_Move_Alt(JitWriter *jit)
1.22 +{
1.23 + //mov edx, eax
1.24 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
1.25 +}
1.26 +
1.27 +inline void WriteOp_Xchg(JitWriter *jit)
1.28 +{
1.29 + //xchg eax, edx
1.30 + IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT);
1.31 +}
1.32 +
1.33 +inline void WriteOp_Push(JitWriter *jit)
1.34 +{
1.35 + //push stack, DAT offset based
1.36 + //sub edi, 4
1.37 + //mov ecx, [ebp+<val>]
1.38 + //mov [edi], ecx
1.39 + cell_t val = jit->read_cell();
1.40 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.41 + //optimize encoding a bit...
1.42 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.43 + {
1.44 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
1.45 + } else {
1.46 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
1.47 + }
1.48 + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
1.49 +}
1.50 +
1.51 +inline void WriteOp_Push_C(JitWriter *jit)
1.52 +{
1.53 + //push stack
1.54 + //mov [edi-4], <val>
1.55 + //sub edi, 4
1.56 + cell_t val = jit->read_cell();
1.57 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4);
1.58 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.59 +}
1.60 +
1.61 +inline void WriteOp_Zero(JitWriter *jit)
1.62 +{
1.63 + //mov [ebp+<val>], 0
1.64 + cell_t val = jit->read_cell();
1.65 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.66 + {
1.67 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val);
1.68 + } else {
1.69 + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val);
1.70 + }
1.71 +}
1.72 +
1.73 +inline void WriteOp_Zero_S(JitWriter *jit)
1.74 +{
1.75 + //mov [ebx+<val>], 0
1.76 + cell_t val = jit->read_cell();
1.77 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.78 + {
1.79 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val);
1.80 + } else {
1.81 + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val);
1.82 + }
1.83 +}
1.84 +
1.85 +inline void WriteOp_Push_S(JitWriter *jit)
1.86 +{
1.87 + //push stack, FRM offset based
1.88 + //sub edi, 4
1.89 + //mov ecx, [ebx+<val>]
1.90 + //mov [edi], ecx
1.91 + cell_t val = jit->read_cell();
1.92 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.93 + //optimize encoding a bit...
1.94 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.95 + {
1.96 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
1.97 + } else {
1.98 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
1.99 + }
1.100 + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
1.101 +}
1.102 +
1.103 +inline void WriteOp_Push_Pri(JitWriter *jit)
1.104 +{
1.105 + //mov [edi-4], eax
1.106 + //sub edi, 4
1.107 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4);
1.108 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.109 +}
1.110 +
1.111 +inline void WriteOp_Push_Alt(JitWriter *jit)
1.112 +{
1.113 + //mov [edi-4], edx
1.114 + //sub edi, 4
1.115 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4);
1.116 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.117 +}
1.118 +
1.119 +inline void WriteOp_Push2_C(JitWriter *jit)
1.120 +{
1.121 + Macro_PushN_C(jit, 2);
1.122 +}
1.123 +
1.124 +inline void WriteOp_Push3_C(JitWriter *jit)
1.125 +{
1.126 + Macro_PushN_C(jit, 3);
1.127 +}
1.128 +
1.129 +inline void WriteOp_Push4_C(JitWriter *jit)
1.130 +{
1.131 + Macro_PushN_C(jit, 4);
1.132 +}
1.133 +
1.134 +inline void WriteOp_Push5_C(JitWriter *jit)
1.135 +{
1.136 + Macro_PushN_C(jit, 5);
1.137 +}
1.138 +
1.139 +inline void WriteOp_Push2_Adr(JitWriter *jit)
1.140 +{
1.141 + Macro_PushN_Addr(jit, 2);
1.142 +}
1.143 +
1.144 +inline void WriteOp_Push3_Adr(JitWriter *jit)
1.145 +{
1.146 + Macro_PushN_Addr(jit, 3);
1.147 +}
1.148 +
1.149 +inline void WriteOp_Push4_Adr(JitWriter *jit)
1.150 +{
1.151 + Macro_PushN_Addr(jit, 4);
1.152 +}
1.153 +
1.154 +inline void WriteOp_Push5_Adr(JitWriter *jit)
1.155 +{
1.156 + Macro_PushN_Addr(jit, 5);
1.157 +}
1.158 +
1.159 +inline void WriteOp_Push2_S(JitWriter *jit)
1.160 +{
1.161 + Macro_PushN_S(jit, 2);
1.162 +}
1.163 +
1.164 +inline void WriteOp_Push3_S(JitWriter *jit)
1.165 +{
1.166 + Macro_PushN_S(jit, 3);
1.167 +}
1.168 +
1.169 +inline void WriteOp_Push4_S(JitWriter *jit)
1.170 +{
1.171 + Macro_PushN_S(jit, 4);
1.172 +}
1.173 +
1.174 +inline void WriteOp_Push5_S(JitWriter *jit)
1.175 +{
1.176 + Macro_PushN_S(jit, 5);
1.177 +}
1.178 +
1.179 +inline void WriteOp_Push5(JitWriter *jit)
1.180 +{
1.181 + Macro_PushN(jit, 5);
1.182 +}
1.183 +
1.184 +inline void WriteOp_Push4(JitWriter *jit)
1.185 +{
1.186 + Macro_PushN(jit, 4);
1.187 +}
1.188 +
1.189 +inline void WriteOp_Push3(JitWriter *jit)
1.190 +{
1.191 + Macro_PushN(jit, 3);
1.192 +}
1.193 +
1.194 +inline void WriteOp_Push2(JitWriter *jit)
1.195 +{
1.196 + Macro_PushN(jit, 2);
1.197 +}
1.198 +
1.199 +inline void WriteOp_Zero_Pri(JitWriter *jit)
1.200 +{
1.201 + //xor eax, eax
1.202 + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
1.203 +}
1.204 +
1.205 +inline void WriteOp_Zero_Alt(JitWriter *jit)
1.206 +{
1.207 + //xor edx, edx
1.208 + IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
1.209 +}
1.210 +
1.211 +inline void WriteOp_Add(JitWriter *jit)
1.212 +{
1.213 + //add eax, edx
1.214 + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.215 +}
1.216 +
1.217 +inline void WriteOp_Sub(JitWriter *jit)
1.218 +{
1.219 + //sub eax, edx
1.220 + IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.221 +}
1.222 +
1.223 +inline void WriteOp_Sub_Alt(JitWriter *jit)
1.224 +{
1.225 + //neg eax
1.226 + //add eax, edx
1.227 + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
1.228 + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.229 +}
1.230 +
1.231 +inline void WriteOp_Proc(JitWriter *jit)
1.232 +{
1.233 + /* align this to four byte boundaries!
1.234 + * This is a decent optimization - x86 likes calls to be properly aligned, otherwise there's an alignment exception
1.235 + * Since all calls are jumped to by relocation, the nops/garbage will never be hit by the runtime process.
1.236 + * Just in case, we guard this memory with INT3 to break into the debugger.
1.237 + */
1.238 + jitoffs_t cur_offs = jit->get_outputpos();
1.239 + if (cur_offs % 4)
1.240 + {
1.241 + cur_offs = 4 - (cur_offs % 4);
1.242 + for (unsigned int i=0; i<cur_offs; i++)
1.243 + {
1.244 + jit->write_ubyte(IA32_INT3);
1.245 + }
1.246 + /* add this amt to the offset we relocated */
1.247 + jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t);
1.248 + jitcode_t rebase = ((CompData *)jit->data)->rebase;
1.249 + *(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos();
1.250 + }
1.251 + //push old frame on stack:
1.252 + //mov ecx, [esi+frm]
1.253 + //mov [edi-4], ecx
1.254 + //sub edi, 8 ;extra un-used slot for non-existant CIP
1.255 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
1.256 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4);
1.257 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
1.258 + //save frame:
1.259 + //mov ecx, edi - get new frame
1.260 + //mov ebx, edi - store frame back
1.261 + //sub ecx, ebp - relocate local frame
1.262 + //mov [esi+frm], ecx
1.263 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
1.264 + IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
1.265 + IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
1.266 + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG);
1.267 +}
1.268 +
1.269 +inline void WriteOp_Lidx_B(JitWriter *jit)
1.270 +{
1.271 + cell_t val = jit->read_cell();
1.272 + //shl eax, <val>
1.273 + //add eax, edx
1.274 + //mov eax, [ebp+eax]
1.275 + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
1.276 + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.277 + Write_Check_VerifyAddr(jit, AMX_REG_PRI);
1.278 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.279 +}
1.280 +
1.281 +inline void WriteOp_Idxaddr_B(JitWriter *jit)
1.282 +{
1.283 + //shl eax, <val>
1.284 + //add eax, edx
1.285 + cell_t val = jit->read_cell();
1.286 + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
1.287 + IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.288 +}
1.289 +
1.290 +inline void WriteOp_Shl(JitWriter *jit)
1.291 +{
1.292 + //mov ecx, edx
1.293 + //shl eax, cl
1.294 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
1.295 + IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
1.296 +}
1.297 +
1.298 +inline void WriteOp_Shr(JitWriter *jit)
1.299 +{
1.300 + //mov ecx, edx
1.301 + //shr eax, cl
1.302 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
1.303 + IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
1.304 +}
1.305 +
1.306 +inline void WriteOp_Sshr(JitWriter *jit)
1.307 +{
1.308 + //mov ecx, edx
1.309 + //sar eax, cl
1.310 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
1.311 + IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
1.312 +}
1.313 +
1.314 +inline void WriteOp_Shl_C_Pri(JitWriter *jit)
1.315 +{
1.316 + //shl eax, <val>
1.317 + jit_uint8_t val = (jit_uint8_t)jit->read_cell();
1.318 + if (val == 1)
1.319 + {
1.320 + IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG);
1.321 + } else {
1.322 + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
1.323 + }
1.324 +}
1.325 +
1.326 +inline void WriteOp_Shl_C_Alt(JitWriter *jit)
1.327 +{
1.328 + //shl edx, <val>
1.329 + jit_uint8_t val = (jit_uint8_t)jit->read_cell();
1.330 + if (val == 1)
1.331 + {
1.332 + IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG);
1.333 + } else {
1.334 + IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
1.335 + }
1.336 +}
1.337 +
1.338 +inline void WriteOp_Shr_C_Pri(JitWriter *jit)
1.339 +{
1.340 + //shr eax, <val>
1.341 + jit_uint8_t val = (jit_uint8_t)jit->read_cell();
1.342 + if (val == 1)
1.343 + {
1.344 + IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG);
1.345 + } else {
1.346 + IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
1.347 + }
1.348 +}
1.349 +
1.350 +inline void WriteOp_Shr_C_Alt(JitWriter *jit)
1.351 +{
1.352 + //shr edx, <val>
1.353 + jit_uint8_t val = (jit_uint8_t)jit->read_cell();
1.354 + if (val == 1)
1.355 + {
1.356 + IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG);
1.357 + } else {
1.358 + IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
1.359 + }
1.360 +}
1.361 +
1.362 +inline void WriteOp_SMul(JitWriter *jit)
1.363 +{
1.364 + //mov ecx, edx
1.365 + //imul edx
1.366 + //mov edx, ecx
1.367 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
1.368 + IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG);
1.369 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
1.370 +}
1.371 +
1.372 +inline void WriteOp_Not(JitWriter *jit)
1.373 +{
1.374 + //test eax, eax
1.375 + //mov eax, 0
1.376 + //sete al
1.377 + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
1.378 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.379 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
1.380 +}
1.381 +
1.382 +inline void WriteOp_Neg(JitWriter *jit)
1.383 +{
1.384 + //neg eax
1.385 + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
1.386 +}
1.387 +
1.388 +inline void WriteOp_Xor(JitWriter *jit)
1.389 +{
1.390 + //xor eax, edx
1.391 + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.392 +}
1.393 +
1.394 +inline void WriteOp_Or(JitWriter *jit)
1.395 +{
1.396 + //or eax, edx
1.397 + IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.398 +}
1.399 +
1.400 +inline void WriteOp_And(JitWriter *jit)
1.401 +{
1.402 + //and eax, edx
1.403 + IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.404 +}
1.405 +
1.406 +inline void WriteOp_Invert(JitWriter *jit)
1.407 +{
1.408 + //not eax
1.409 + IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG);
1.410 +}
1.411 +
1.412 +inline void WriteOp_Add_C(JitWriter *jit)
1.413 +{
1.414 + //add eax, <val>
1.415 + cell_t val = jit->read_cell();
1.416 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.417 + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
1.418 + else
1.419 + IA32_Add_Eax_Imm32(jit, val);
1.420 +}
1.421 +
1.422 +inline void WriteOp_SMul_C(JitWriter *jit)
1.423 +{
1.424 + //imul eax, <val>
1.425 + cell_t val = jit->read_cell();
1.426 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.427 + IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
1.428 + else
1.429 + IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val);
1.430 +}
1.431 +
1.432 +inline void WriteOp_Sign_Pri(JitWriter *jit)
1.433 +{
1.434 + //shl eax, 24
1.435 + //sar eax, 24
1.436 + IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
1.437 + IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
1.438 +}
1.439 +
1.440 +inline void WriteOp_Sign_Alt(JitWriter *jit)
1.441 +{
1.442 + //shl edx, 24
1.443 + //sar edx, 24
1.444 + IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
1.445 + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
1.446 +}
1.447 +
1.448 +inline void WriteOp_Eq(JitWriter *jit)
1.449 +{
1.450 + //cmp eax, edx ; PRI == ALT ?
1.451 + //mov eax, 0
1.452 + //sete al
1.453 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.454 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.455 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
1.456 +}
1.457 +
1.458 +inline void WriteOp_Neq(JitWriter *jit)
1.459 +{
1.460 + //cmp eax, edx ; PRI != ALT ?
1.461 + //mov eax, 0
1.462 + //setne al
1.463 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.464 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.465 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE);
1.466 +}
1.467 +
1.468 +inline void WriteOp_Sless(JitWriter *jit)
1.469 +{
1.470 + //cmp eax, edx ; PRI < ALT ? (signed)
1.471 + //mov eax, 0
1.472 + //setl al
1.473 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.474 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.475 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L);
1.476 +}
1.477 +
1.478 +inline void WriteOp_Sleq(JitWriter *jit)
1.479 +{
1.480 + //cmp eax, edx ; PRI <= ALT ? (signed)
1.481 + //mov eax, 0
1.482 + //setle al
1.483 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.484 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.485 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE);
1.486 +}
1.487 +
1.488 +inline void WriteOp_Sgrtr(JitWriter *jit)
1.489 +{
1.490 + //cmp eax, edx ; PRI > ALT ? (signed)
1.491 + //mov eax, 0
1.492 + //setg al
1.493 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.494 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.495 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G);
1.496 +}
1.497 +
1.498 +inline void WriteOp_Sgeq(JitWriter *jit)
1.499 +{
1.500 + //cmp eax, edx ; PRI >= ALT ? (signed)
1.501 + //mov eax, 0
1.502 + //setge al
1.503 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.504 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.505 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE);
1.506 +}
1.507 +
1.508 +inline void WriteOp_Eq_C_Pri(JitWriter *jit)
1.509 +{
1.510 + //cmp eax, <val> ; PRI == value ?
1.511 + //mov eax, 0
1.512 + //sete al
1.513 + cell_t val = jit->read_cell();
1.514 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.515 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
1.516 + else
1.517 + IA32_Cmp_Eax_Imm32(jit, val);
1.518 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
1.519 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
1.520 +}
1.521 +
1.522 +inline void WriteOp_Eq_C_Alt(JitWriter *jit)
1.523 +{
1.524 + //xor eax, eax
1.525 + //cmp edx, <val> ; ALT == value ?
1.526 + //sete al
1.527 + cell_t val = jit->read_cell();
1.528 + IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
1.529 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.530 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val);
1.531 + else
1.532 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val);
1.533 + IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
1.534 +}
1.535 +
1.536 +inline void WriteOp_Inc_Pri(JitWriter *jit)
1.537 +{
1.538 + //add eax, 1
1.539 + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
1.540 +}
1.541 +
1.542 +inline void WriteOp_Inc_Alt(JitWriter *jit)
1.543 +{
1.544 + //add edx, 1
1.545 + IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
1.546 +}
1.547 +
1.548 +inline void WriteOp_Inc(JitWriter *jit)
1.549 +{
1.550 + //add [ebp+<val>], 1
1.551 + cell_t val = jit->read_cell();
1.552 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.553 + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
1.554 + else
1.555 + IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
1.556 +}
1.557 +
1.558 +inline void WriteOp_Inc_S(JitWriter *jit)
1.559 +{
1.560 + //add [ebx+<val>], 1
1.561 + cell_t val = jit->read_cell();
1.562 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.563 + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
1.564 + else
1.565 + IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
1.566 +}
1.567 +
1.568 +inline void WriteOp_Inc_I(JitWriter *jit)
1.569 +{
1.570 + //add [ebp+eax], 1
1.571 + IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
1.572 +}
1.573 +
1.574 +inline void WriteOp_Dec_Pri(JitWriter *jit)
1.575 +{
1.576 + //sub eax, 1
1.577 + IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
1.578 +}
1.579 +
1.580 +inline void WriteOp_Dec_Alt(JitWriter *jit)
1.581 +{
1.582 + //sub edx, 1
1.583 + IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
1.584 +}
1.585 +
1.586 +inline void WriteOp_Dec(JitWriter *jit)
1.587 +{
1.588 + //sub [ebp+<val>], 1
1.589 + cell_t val = jit->read_cell();
1.590 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.591 + {
1.592 + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
1.593 + } else {
1.594 + IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
1.595 + }
1.596 +}
1.597 +
1.598 +inline void WriteOp_Dec_S(JitWriter *jit)
1.599 +{
1.600 + //sub [ebx+<val>], 1
1.601 + cell_t val = jit->read_cell();
1.602 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.603 + {
1.604 + IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
1.605 + } else {
1.606 + IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
1.607 + }
1.608 +}
1.609 +
1.610 +inline void WriteOp_Dec_I(JitWriter *jit)
1.611 +{
1.612 + //sub [ebp+eax], 1
1.613 + IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
1.614 +}
1.615 +
1.616 +inline void WriteOp_Load_Pri(JitWriter *jit)
1.617 +{
1.618 + //mov eax, [ebp+<val>]
1.619 + cell_t val = jit->read_cell();
1.620 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.621 + {
1.622 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
1.623 + } else {
1.624 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
1.625 + }
1.626 +}
1.627 +
1.628 +inline void WriteOp_Load_Alt(JitWriter *jit)
1.629 +{
1.630 + //mov edx, [ebp+<val>]
1.631 + cell_t val = jit->read_cell();
1.632 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.633 + {
1.634 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
1.635 + } else {
1.636 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
1.637 + }
1.638 +}
1.639 +
1.640 +inline void WriteOp_Load_S_Pri(JitWriter *jit)
1.641 +{
1.642 + //mov eax, [ebx+<val>]
1.643 + cell_t val = jit->read_cell();
1.644 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.645 + {
1.646 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
1.647 + } else {
1.648 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
1.649 + }
1.650 +}
1.651 +
1.652 +inline void WriteOp_Load_S_Alt(JitWriter *jit)
1.653 +{
1.654 + //mov edx, [ebx+<val>]
1.655 + cell_t val = jit->read_cell();
1.656 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.657 + {
1.658 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
1.659 + } else {
1.660 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
1.661 + }
1.662 +}
1.663 +
1.664 +inline void WriteOp_Lref_Pri(JitWriter *jit)
1.665 +{
1.666 + //mov eax, [ebp+<val>]
1.667 + //mov eax, [ebp+eax]
1.668 + cell_t val = jit->read_cell();
1.669 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.670 + {
1.671 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
1.672 + } else {
1.673 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
1.674 + }
1.675 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.676 +}
1.677 +
1.678 +inline void WriteOp_Lref_Alt(JitWriter *jit)
1.679 +{
1.680 + //mov edx, [ebp+<val>]
1.681 + //mov edx, [ebp+edx]
1.682 + cell_t val = jit->read_cell();
1.683 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.684 + {
1.685 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
1.686 + } else {
1.687 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
1.688 + }
1.689 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
1.690 +}
1.691 +
1.692 +inline void WriteOp_Lref_S_Pri(JitWriter *jit)
1.693 +{
1.694 + //mov eax, [ebx+<val>]
1.695 + //mov eax, [ebp+eax]
1.696 + cell_t val = jit->read_cell();
1.697 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.698 + {
1.699 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
1.700 + } else {
1.701 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
1.702 + }
1.703 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.704 +}
1.705 +
1.706 +inline void WriteOp_Lref_S_Alt(JitWriter *jit)
1.707 +{
1.708 + //mov edx, [ebx+<val>]
1.709 + //mov edx, [ebp+edx]
1.710 + cell_t val = jit->read_cell();
1.711 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.712 + {
1.713 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
1.714 + } else {
1.715 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
1.716 + }
1.717 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
1.718 +}
1.719 +
1.720 +inline void WriteOp_Const_Pri(JitWriter *jit)
1.721 +{
1.722 + //mov eax, <val>
1.723 + cell_t val = jit->read_cell();
1.724 + IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val);
1.725 +}
1.726 +
1.727 +inline void WriteOp_Const_Alt(JitWriter *jit)
1.728 +{
1.729 + //mov edx, <val>
1.730 + cell_t val = jit->read_cell();
1.731 + IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val);
1.732 +}
1.733 +
1.734 +inline void WriteOp_Addr_Pri(JitWriter *jit)
1.735 +{
1.736 + //mov eax, [esi+frm]
1.737 + //add eax, <val>
1.738 + cell_t val = jit->read_cell();
1.739 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
1.740 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.741 + {
1.742 + IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
1.743 + } else {
1.744 + IA32_Add_Eax_Imm32(jit, val);
1.745 + }
1.746 +}
1.747 +
1.748 +inline void WriteOp_Addr_Alt(JitWriter *jit)
1.749 +{
1.750 + //mov edx, [esi+frm]
1.751 + //add edx, <val>
1.752 + cell_t val = jit->read_cell();
1.753 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG);
1.754 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.755 + {
1.756 + IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG);
1.757 + } else {
1.758 + IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG);
1.759 + }
1.760 +}
1.761 +
1.762 +inline void WriteOp_Stor_Pri(JitWriter *jit)
1.763 +{
1.764 + //mov [ebp+<val>], eax
1.765 + cell_t val = jit->read_cell();
1.766 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.767 + {
1.768 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val);
1.769 + } else {
1.770 + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val);
1.771 + }
1.772 +}
1.773 +
1.774 +inline void WriteOp_Stor_Alt(JitWriter *jit)
1.775 +{
1.776 + //mov [ebp+<val>], edx
1.777 + cell_t val = jit->read_cell();
1.778 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.779 + {
1.780 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val);
1.781 + } else {
1.782 + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val);
1.783 + }
1.784 +}
1.785 +
1.786 +inline void WriteOp_Stor_S_Pri(JitWriter *jit)
1.787 +{
1.788 + //mov [ebx+<val>], eax
1.789 + cell_t val = jit->read_cell();
1.790 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.791 + {
1.792 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val);
1.793 + } else {
1.794 + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val);
1.795 + }
1.796 +}
1.797 +
1.798 +inline void WriteOp_Stor_S_Alt(JitWriter *jit)
1.799 +{
1.800 + //mov [ebx+<val>], edx
1.801 + cell_t val = jit->read_cell();
1.802 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.803 + {
1.804 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val);
1.805 + } else {
1.806 + IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val);
1.807 + }
1.808 +}
1.809 +
1.810 +inline void WriteOp_Idxaddr(JitWriter *jit)
1.811 +{
1.812 + //lea eax, [edx+4*eax]
1.813 + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
1.814 +}
1.815 +
1.816 +inline void WriteOp_Sref_Pri(JitWriter *jit)
1.817 +{
1.818 + //mov ecx, [ebp+<val>]
1.819 + //mov [ebp+ecx], eax
1.820 + cell_t val = jit->read_cell();
1.821 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.822 + {
1.823 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
1.824 + } else {
1.825 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
1.826 + }
1.827 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
1.828 +}
1.829 +
1.830 +inline void WriteOp_Sref_Alt(JitWriter *jit)
1.831 +{
1.832 + //mov ecx, [ebp+<val>]
1.833 + //mov [ebp+ecx], edx
1.834 + cell_t val = jit->read_cell();
1.835 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.836 + {
1.837 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
1.838 + } else {
1.839 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
1.840 + }
1.841 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
1.842 +}
1.843 +
1.844 +inline void WriteOp_Sref_S_Pri(JitWriter *jit)
1.845 +{
1.846 + //mov ecx, [ebx+<val>]
1.847 + //mov [ebp+ecx], eax
1.848 + cell_t val = jit->read_cell();
1.849 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.850 + {
1.851 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
1.852 + } else {
1.853 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
1.854 + }
1.855 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
1.856 +}
1.857 +
1.858 +inline void WriteOp_Sref_S_Alt(JitWriter *jit)
1.859 +{
1.860 + //mov ecx, [ebx+<val>]
1.861 + //mov [ebp+ecx], edx
1.862 + cell_t val = jit->read_cell();
1.863 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.864 + {
1.865 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
1.866 + } else {
1.867 + IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
1.868 + }
1.869 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
1.870 +}
1.871 +
1.872 +inline void WriteOp_Pop_Pri(JitWriter *jit)
1.873 +{
1.874 + //mov eax, [edi]
1.875 + //add edi, 4
1.876 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
1.877 + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.878 +}
1.879 +
1.880 +inline void WriteOp_Pop_Alt(JitWriter *jit)
1.881 +{
1.882 + //mov edx, [edi]
1.883 + //add edi, 4
1.884 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
1.885 + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.886 +}
1.887 +
1.888 +inline void WriteOp_Swap_Pri(JitWriter *jit)
1.889 +{
1.890 + //add [edi], eax
1.891 + //sub eax, [edi]
1.892 + //add [edi], eax
1.893 + //neg eax
1.894 + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
1.895 + IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
1.896 + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
1.897 + IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
1.898 +}
1.899 +
1.900 +inline void WriteOp_Swap_Alt(JitWriter *jit)
1.901 +{
1.902 + //add [edi], edx
1.903 + //sub edx, [edi]
1.904 + //add [edi], edx
1.905 + //neg edx
1.906 + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
1.907 + IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
1.908 + IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
1.909 + IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG);
1.910 +}
1.911 +
1.912 +inline void WriteOp_PushAddr(JitWriter *jit)
1.913 +{
1.914 + //mov ecx, [esi+frm] ;get address (offset from frame)
1.915 + //sub edi, 4
1.916 + //add ecx, <val>
1.917 + //mov [edi], ecx
1.918 + cell_t val = jit->read_cell();
1.919 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
1.920 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.921 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.922 + {
1.923 + IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG);
1.924 + } else {
1.925 + IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG);
1.926 + }
1.927 + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
1.928 +}
1.929 +
1.930 +inline void WriteOp_Movs(JitWriter *jit)
1.931 +{
1.932 + //cld
1.933 + //push esi
1.934 + //push edi
1.935 + //lea esi, [ebp+eax]
1.936 + //lea edi, [ebp+edx]
1.937 + //if dword:
1.938 + // mov ecx, dword
1.939 + // rep movsd
1.940 + //if byte:
1.941 + // mov ecx, byte
1.942 + // rep movsb
1.943 + //pop edi
1.944 + //pop esi
1.945 + cell_t val = jit->read_cell();
1.946 + unsigned int dwords = val >> 2;
1.947 + unsigned int bytes = val & 0x3;
1.948 +
1.949 + IA32_Cld(jit);
1.950 + IA32_Push_Reg(jit, REG_ESI);
1.951 + IA32_Push_Reg(jit, REG_EDI);
1.952 + IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.953 + IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
1.954 + if (dwords)
1.955 + {
1.956 + IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords);
1.957 + IA32_Rep(jit);
1.958 + IA32_Movsd(jit);
1.959 + }
1.960 + if (bytes)
1.961 + {
1.962 + IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes);
1.963 + IA32_Rep(jit);
1.964 + IA32_Movsb(jit);
1.965 + }
1.966 + IA32_Pop_Reg(jit, REG_EDI);
1.967 + IA32_Pop_Reg(jit, REG_ESI);
1.968 +}
1.969 +
1.970 +inline void WriteOp_Fill(JitWriter *jit)
1.971 +{
1.972 + //push edi
1.973 + //lea edi, [ebp+edx]
1.974 + //mov ecx, <val> >> 2
1.975 + //cld
1.976 + //rep stosd
1.977 + //pop edi
1.978 + unsigned int val = jit->read_cell() >> 2;
1.979 +
1.980 + IA32_Push_Reg(jit, REG_EDI);
1.981 + IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
1.982 + IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
1.983 + IA32_Cld(jit);
1.984 + IA32_Rep(jit);
1.985 + IA32_Stosd(jit);
1.986 + IA32_Pop_Reg(jit, REG_EDI);
1.987 +}
1.988 +
1.989 +inline void WriteOp_GenArray(JitWriter *jit, bool autozero)
1.990 +{
1.991 + cell_t val = jit->read_cell();
1.992 + if (val == 1)
1.993 + {
1.994 + /* flat array. we can generate this without indirection tables. */
1.995 + /* Note that we can overwrite ALT because technically STACK should be destroying ALT */
1.996 + //mov edx, [esi+info.heap]
1.997 + //mov ecx, [edi]
1.998 + //mov [edi], edx ;store base of array into stack
1.999 + //lea edx, [edx+ecx*4] ;get the final new heap pointer
1.1000 + //mov [esi+info.heap], edx ;store heap pointer back
1.1001 + //add edx, ebp ;relocate
1.1002 + //cmp edx, edi ;compare against stack pointer
1.1003 + //jae :error ;error out if not enough space
1.1004 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
1.1005 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
1.1006 + IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
1.1007 + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4);
1.1008 + IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP);
1.1009 + IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG);
1.1010 + IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG);
1.1011 + IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow);
1.1012 +
1.1013 + WriteOp_Tracker_Push_Reg(jit, REG_ECX);
1.1014 +
1.1015 + if (autozero)
1.1016 + {
1.1017 + /* Zero out the array - inline a quick fill */
1.1018 + //push eax ;save pri
1.1019 + //push edi ;save stk
1.1020 + //xor eax, eax ;zero source
1.1021 + //mov edi, [edi] ;get heap ptr out of the stack
1.1022 + //add edi, ebp ;relocate
1.1023 + //cld ;clear direction flag
1.1024 + //rep stosd ;copy (note: ECX is sane from above)
1.1025 + //pop edi ;pop stk
1.1026 + //pop eax ;pop pri
1.1027 + IA32_Push_Reg(jit, REG_EAX);
1.1028 + IA32_Push_Reg(jit, REG_EDI);
1.1029 + IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG);
1.1030 + IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG);
1.1031 + IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
1.1032 + IA32_Cld(jit);
1.1033 + IA32_Rep(jit);
1.1034 + IA32_Stosd(jit);
1.1035 + IA32_Pop_Reg(jit, REG_EDI);
1.1036 + IA32_Pop_Reg(jit, REG_EAX);
1.1037 + }
1.1038 + } else {
1.1039 + //mov ecx, num_dims
1.1040 + //mov edx, 0/1
1.1041 + //call [genarray]
1.1042 + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val);
1.1043 + if (autozero)
1.1044 + {
1.1045 + IA32_Mov_Reg_Imm32(jit, REG_EDX, 1);
1.1046 + } else {
1.1047 + IA32_Mov_Reg_Imm32(jit, REG_EDX, 0);
1.1048 + }
1.1049 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1050 + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_genarray);
1.1051 + }
1.1052 +}
1.1053 +
1.1054 +inline void WriteOp_Load_Both(JitWriter *jit)
1.1055 +{
1.1056 + WriteOp_Load_Pri(jit);
1.1057 + WriteOp_Load_Alt(jit);
1.1058 +}
1.1059 +
1.1060 +inline void WriteOp_Load_S_Both(JitWriter *jit)
1.1061 +{
1.1062 + WriteOp_Load_S_Pri(jit);
1.1063 + WriteOp_Load_S_Alt(jit);
1.1064 +}
1.1065 +
1.1066 +inline void WriteOp_Const(JitWriter *jit)
1.1067 +{
1.1068 + //mov [ebp+<addr>], <val>
1.1069 + cell_t addr = jit->read_cell();
1.1070 + cell_t val = jit->read_cell();
1.1071 + if (addr < SCHAR_MAX && addr > SCHAR_MIN)
1.1072 + {
1.1073 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr);
1.1074 + } else {
1.1075 + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr);
1.1076 + }
1.1077 +}
1.1078 +
1.1079 +inline void WriteOp_Const_S(JitWriter *jit)
1.1080 +{
1.1081 + //mov [ebx+<offs>], <val>
1.1082 + cell_t offs = jit->read_cell();
1.1083 + cell_t val = jit->read_cell();
1.1084 + if (offs < SCHAR_MAX && offs > SCHAR_MIN)
1.1085 + {
1.1086 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs);
1.1087 + } else {
1.1088 + IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs);
1.1089 + }
1.1090 +}
1.1091 +
1.1092 +inline void WriteOp_Load_I(JitWriter *jit)
1.1093 +{
1.1094 + //mov eax, [ebp+eax]
1.1095 + Write_Check_VerifyAddr(jit, AMX_REG_PRI);
1.1096 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.1097 +}
1.1098 +
1.1099 +inline void WriteOp_Lodb_I(JitWriter *jit)
1.1100 +{
1.1101 + Write_Check_VerifyAddr(jit, AMX_REG_PRI);
1.1102 +
1.1103 + //mov eax, [ebp+eax]
1.1104 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.1105 +
1.1106 + //and eax, <bitmask>
1.1107 + cell_t val = jit->read_cell();
1.1108 + switch(val)
1.1109 + {
1.1110 + case 1:
1.1111 + {
1.1112 + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x000000FF);
1.1113 + break;
1.1114 + }
1.1115 + case 2:
1.1116 + {
1.1117 + IA32_And_Rm_Imm32(jit, AMX_REG_PRI, 0x0000FFFF);
1.1118 + break;
1.1119 + }
1.1120 + }
1.1121 +}
1.1122 +
1.1123 +inline void WriteOp_Stor_I(JitWriter *jit)
1.1124 +{
1.1125 + //mov [ebp+edx], eax
1.1126 + Write_Check_VerifyAddr(jit, AMX_REG_ALT);
1.1127 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
1.1128 +}
1.1129 +
1.1130 +inline void WriteOp_Strb_I(JitWriter *jit)
1.1131 +{
1.1132 + Write_Check_VerifyAddr(jit, AMX_REG_ALT);
1.1133 + //mov [ebp+edx], eax
1.1134 + cell_t val = jit->read_cell();
1.1135 + switch (val)
1.1136 + {
1.1137 + case 1:
1.1138 + {
1.1139 + IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
1.1140 + break;
1.1141 + }
1.1142 + case 2:
1.1143 + {
1.1144 + IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
1.1145 + break;
1.1146 + }
1.1147 + case 4:
1.1148 + {
1.1149 + IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
1.1150 + break;
1.1151 + }
1.1152 + }
1.1153 +}
1.1154 +
1.1155 +inline void WriteOp_Lidx(JitWriter *jit)
1.1156 +{
1.1157 + //lea eax, [edx+4*eax]
1.1158 + //mov eax, [ebp+eax]
1.1159 + IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
1.1160 + Write_Check_VerifyAddr(jit, AMX_REG_PRI);
1.1161 + IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
1.1162 +}
1.1163 +
1.1164 +inline void WriteOp_Stack(JitWriter *jit)
1.1165 +{
1.1166 + //add edi, <val>
1.1167 + cell_t val = jit->read_cell();
1.1168 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.1169 + {
1.1170 + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG);
1.1171 + } else {
1.1172 + IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG);
1.1173 + }
1.1174 +
1.1175 + if (val > 0)
1.1176 + {
1.1177 + Write_CheckStack_Min(jit);
1.1178 + } else if (val < 0) {
1.1179 + Write_CheckStack_Low(jit);
1.1180 + }
1.1181 +}
1.1182 +
1.1183 +inline void WriteOp_Heap(JitWriter *jit)
1.1184 +{
1.1185 + //mov edx, [esi+hea]
1.1186 + //add [esi+hea], <val>
1.1187 + cell_t val = jit->read_cell();
1.1188 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
1.1189 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.1190 + {
1.1191 + IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP);
1.1192 + } else {
1.1193 + IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP);
1.1194 + }
1.1195 +
1.1196 + /* NOTE: Backwards from op.stack */
1.1197 + if (val > 0)
1.1198 + {
1.1199 + Write_CheckHeap_Low(jit);
1.1200 + } else if (val < 0) {
1.1201 + Write_CheckHeap_Min(jit);
1.1202 + }
1.1203 +}
1.1204 +
1.1205 +inline void WriteOp_SDiv(JitWriter *jit)
1.1206 +{
1.1207 + //mov ecx, edx
1.1208 + //mov edx, eax
1.1209 + //sar edx, 31
1.1210 + //idiv ecx
1.1211 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
1.1212 + IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
1.1213 + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
1.1214 + Write_Check_DivZero(jit, AMX_REG_TMP);
1.1215 + IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
1.1216 +}
1.1217 +
1.1218 +inline void WriteOp_SDiv_Alt(JitWriter *jit)
1.1219 +{
1.1220 + //mov ecx, eax
1.1221 + //mov eax, edx
1.1222 + //sar edx, 31
1.1223 + //idiv ecx
1.1224 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
1.1225 + IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1226 + IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
1.1227 + Write_Check_DivZero(jit, AMX_REG_TMP);
1.1228 + IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
1.1229 +}
1.1230 +
1.1231 +inline void WriteOp_Retn(JitWriter *jit)
1.1232 +{
1.1233 + //mov ebx, [edi+4] - get old frm
1.1234 + //add edi, 8 - pop stack
1.1235 + //mov [esi+frm], ebx - restore frame pointer
1.1236 + //add ebx, ebp - relocate
1.1237 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4);
1.1238 + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
1.1239 + IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG);
1.1240 + IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG);
1.1241 +
1.1242 + /* pop params */
1.1243 + //mov ecx, [edi]
1.1244 + //lea edi, [edi+ecx*4+4]
1.1245 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
1.1246 + IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4);
1.1247 +
1.1248 + //ret - return (EIP on real stack!)
1.1249 + IA32_Return(jit);
1.1250 +}
1.1251 +
1.1252 +inline void WriteOp_Call(JitWriter *jit)
1.1253 +{
1.1254 + cell_t offs = jit->read_cell();
1.1255 +
1.1256 + jitoffs_t jmp = IA32_Call_Imm32(jit, 0);
1.1257 + IA32_Write_Jump32(jit, jmp, RelocLookup(jit, offs, false));
1.1258 +}
1.1259 +
1.1260 +inline void WriteOp_Bounds(JitWriter *jit)
1.1261 +{
1.1262 + cell_t val = jit->read_cell();
1.1263 +
1.1264 + //cmp eax, <val>
1.1265 + //ja :error
1.1266 + if (val < SCHAR_MAX && val > SCHAR_MIN)
1.1267 + {
1.1268 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
1.1269 + } else {
1.1270 + IA32_Cmp_Eax_Imm32(jit, val);
1.1271 + }
1.1272 + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds);
1.1273 +}
1.1274 +
1.1275 +inline void WriteOp_Halt(JitWriter *jit)
1.1276 +{
1.1277 + //mov ecx, [esi+ret]
1.1278 + //mov [ecx], eax
1.1279 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL);
1.1280 + IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG);
1.1281 +
1.1282 + /* :TODO:
1.1283 + * We don't support sleeping or halting with weird values.
1.1284 + * So we're omitting the mov eax <val> that was here.
1.1285 + */
1.1286 + jit->read_cell();
1.1287 +
1.1288 + CompData *data = (CompData *)jit->data;
1.1289 + IA32_Jump_Imm32_Abs(jit, data->jit_return);
1.1290 +}
1.1291 +
1.1292 +inline void WriteOp_Break(JitWriter *jit)
1.1293 +{
1.1294 + CompData *data = (CompData *)jit->data;
1.1295 + if (data->debug)
1.1296 + {
1.1297 + //mov ecx, <cip>
1.1298 + jitoffs_t wr = IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, 0);
1.1299 + jitoffs_t save = jit->get_outputpos();
1.1300 + jit->set_outputpos(wr);
1.1301 + jit->write_uint32((uint32_t)(jit->outbase + wr));
1.1302 + jit->set_outputpos(save);
1.1303 +
1.1304 + wr = IA32_Call_Imm32(jit, 0);
1.1305 + IA32_Write_Jump32(jit, wr, data->jit_break);
1.1306 + }
1.1307 +}
1.1308 +
1.1309 +inline void WriteOp_Jump(JitWriter *jit)
1.1310 +{
1.1311 + //jmp <offs>
1.1312 + cell_t amx_offs = jit->read_cell();
1.1313 + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, amx_offs, false));
1.1314 +}
1.1315 +
1.1316 +inline void WriteOp_Jzer(JitWriter *jit)
1.1317 +{
1.1318 + //test eax, eax
1.1319 + //jz <target>
1.1320 + cell_t target = jit->read_cell();
1.1321 + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
1.1322 + IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, RelocLookup(jit, target, false));
1.1323 +}
1.1324 +
1.1325 +inline void WriteOp_Jnz(JitWriter *jit)
1.1326 +{
1.1327 + //test eax, eax
1.1328 + //jnz <target>
1.1329 + cell_t target = jit->read_cell();
1.1330 + IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
1.1331 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, RelocLookup(jit, target, false));
1.1332 +}
1.1333 +
1.1334 +inline void WriteOp_Jeq(JitWriter *jit)
1.1335 +{
1.1336 + //cmp eax, edx
1.1337 + //je <target>
1.1338 + cell_t target = jit->read_cell();
1.1339 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1340 + IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, target, false));
1.1341 +}
1.1342 +
1.1343 +inline void WriteOp_Jneq(JitWriter *jit)
1.1344 +{
1.1345 + //cmp eax, edx
1.1346 + //jne <target>
1.1347 + cell_t target = jit->read_cell();
1.1348 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1349 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, RelocLookup(jit, target, false));
1.1350 +}
1.1351 +
1.1352 +inline void WriteOp_Jsless(JitWriter *jit)
1.1353 +{
1.1354 + //cmp eax, edx
1.1355 + //jl <target>
1.1356 + cell_t target = jit->read_cell();
1.1357 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1358 + IA32_Jump_Cond_Imm32_Abs(jit, CC_L, RelocLookup(jit, target, false));
1.1359 +}
1.1360 +
1.1361 +inline void WriteOp_Jsleq(JitWriter *jit)
1.1362 +{
1.1363 + //cmp eax, edx
1.1364 + //jle <target>
1.1365 + cell_t target = jit->read_cell();
1.1366 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1367 + IA32_Jump_Cond_Imm32_Abs(jit, CC_LE, RelocLookup(jit, target, false));
1.1368 +}
1.1369 +
1.1370 +inline void WriteOp_JsGrtr(JitWriter *jit)
1.1371 +{
1.1372 + //cmp eax, edx
1.1373 + //jg <target>
1.1374 + cell_t target = jit->read_cell();
1.1375 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1376 + IA32_Jump_Cond_Imm32_Abs(jit, CC_G, RelocLookup(jit, target, false));
1.1377 +}
1.1378 +
1.1379 +inline void WriteOp_JsGeq(JitWriter *jit)
1.1380 +{
1.1381 + //cmp eax, edx
1.1382 + //jge <target>
1.1383 + cell_t target = jit->read_cell();
1.1384 + IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
1.1385 + IA32_Jump_Cond_Imm32_Abs(jit, CC_GE, RelocLookup(jit, target, false));
1.1386 +}
1.1387 +
1.1388 +inline void WriteOp_Switch(JitWriter *jit)
1.1389 +{
1.1390 + cell_t offs = jit->read_cell();
1.1391 + cell_t *tbl = (cell_t *)((char *)jit->inbase + offs + sizeof(cell_t));
1.1392 +
1.1393 + struct casetbl
1.1394 + {
1.1395 + cell_t val;
1.1396 + cell_t offs;
1.1397 + };
1.1398 +
1.1399 + /* Read the number of cases, then advance by one */
1.1400 + cell_t num_cases = *tbl++;
1.1401 + if (!num_cases)
1.1402 + {
1.1403 + /* Special treatment for 0 cases */
1.1404 + //jmp <default>
1.1405 + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false));
1.1406 + } else {
1.1407 + /* Check if the case layout is fully sequential */
1.1408 + casetbl *iter = (casetbl *)(tbl + 1);
1.1409 + casetbl *cases = iter;
1.1410 + cell_t first = iter[0].val;
1.1411 + cell_t last = first;
1.1412 + bool sequential = true;
1.1413 + for (cell_t i=1; i<num_cases; i++)
1.1414 + {
1.1415 + if (iter[i].val != ++last)
1.1416 + {
1.1417 + sequential = false;
1.1418 + break;
1.1419 + }
1.1420 + }
1.1421 + /* Time to generate.
1.1422 + * First check whether the bounds are correct: if (a < LOW || a > HIGH)
1.1423 + * This check is valid for both sequential and non-sequential.
1.1424 + */
1.1425 + cell_t low_bound = cases[0].val;
1.1426 + if (low_bound != 0)
1.1427 + {
1.1428 + /* negate it so we'll get a lower bound of 0 */
1.1429 + //lea ecx, [eax-<LOWER_BOUND>]
1.1430 + low_bound = -low_bound;
1.1431 + if (low_bound > SCHAR_MIN && low_bound < SCHAR_MAX)
1.1432 + {
1.1433 + IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
1.1434 + } else {
1.1435 + IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
1.1436 + }
1.1437 + }
1.1438 + cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val);
1.1439 + //cmp ecx, <UPPER BOUND BOUND>
1.1440 + if (high_bound > SCHAR_MIN && high_bound < SCHAR_MAX)
1.1441 + {
1.1442 + IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound);
1.1443 + } else {
1.1444 + IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound);
1.1445 + }
1.1446 + //ja <default case>
1.1447 + IA32_Jump_Cond_Imm32_Abs(jit, CC_A, RelocLookup(jit, *tbl, false));
1.1448 +
1.1449 + /**
1.1450 + * Now we've taken the default case out of the way, it's time to do the
1.1451 + * full check, which is different for sequential vs. non-sequential.
1.1452 + */
1.1453 + if (sequential)
1.1454 + {
1.1455 + /* we're now theoretically guaranteed to be jumping to a correct offset.
1.1456 + * ECX still has the correctly bound offset in it, luckily!
1.1457 + * thus, we simply need to relocate ECX and store the cases.
1.1458 + */
1.1459 + //lea ecx, [ecx*4]
1.1460 + //add ecx, <case table start>
1.1461 + IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0);
1.1462 + jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG);
1.1463 + IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG);
1.1464 + /* The case table starts here. Go back and write the output pointer. */
1.1465 + jitoffs_t cur_pos = jit->get_outputpos();
1.1466 + jit->set_outputpos(tbl_offs);
1.1467 + jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos));
1.1468 + jit->set_outputpos(cur_pos);
1.1469 + //now we can write the case table, finally!
1.1470 + jit_uint32_t base = (jit_uint32_t)jit->outbase;
1.1471 + for (cell_t i=0; i<num_cases; i++)
1.1472 + {
1.1473 + jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false));
1.1474 + }
1.1475 + } else {
1.1476 + /* The slow version. Go through each case and generate a check.
1.1477 + * In the future we should replace case tables of more than ~8 cases with a
1.1478 + * hash table lookup.
1.1479 + * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case,
1.1480 + * but only if we're under N cases or so!
1.1481 + * :THOUGHT: Write out a static btree lookup :)
1.1482 + */
1.1483 + cell_t val;
1.1484 + for (cell_t i=0; i<num_cases; i++)
1.1485 + {
1.1486 + val = cases[i].val;
1.1487 + //cmp eax, <val> OR cmp al, <val>
1.1488 + if (val > SCHAR_MIN && val < SCHAR_MAX)
1.1489 + {
1.1490 + IA32_Cmp_Al_Imm8(jit, val);
1.1491 + } else {
1.1492 + IA32_Cmp_Eax_Imm32(jit, cases[i].val);
1.1493 + }
1.1494 + IA32_Jump_Cond_Imm32_Abs(jit, CC_E, RelocLookup(jit, cases[i].offs, false));
1.1495 + }
1.1496 + /* After all this, jump to the default case! */
1.1497 + IA32_Jump_Imm32_Abs(jit, RelocLookup(jit, *tbl, false));
1.1498 + }
1.1499 + }
1.1500 +}
1.1501 +
1.1502 +inline void WriteOp_Casetbl(JitWriter *jit)
1.1503 +{
1.1504 + /* do nothing here, switch does all ze work */
1.1505 + cell_t num_cases = jit->read_cell();
1.1506 +
1.1507 + /* Two cells per case, one extra case for the default jump */
1.1508 + num_cases = (num_cases * 2) + 1;
1.1509 + jit->inptr += num_cases;
1.1510 +}
1.1511 +
1.1512 +inline void WriteOp_Sysreq_C(JitWriter *jit)
1.1513 +{
1.1514 + /* store the number of parameters on the stack,
1.1515 + * and store the native index as well.
1.1516 + */
1.1517 + cell_t native_index = jit->read_cell();
1.1518 +
1.1519 + if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num)
1.1520 + {
1.1521 + ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM;
1.1522 + return;
1.1523 + }
1.1524 +
1.1525 + //mov ecx, <native_index>
1.1526 + IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index);
1.1527 +
1.1528 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1529 + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c);
1.1530 +}
1.1531 +
1.1532 +inline void WriteOp_Sysreq_N_NoInline(JitWriter *jit)
1.1533 +{
1.1534 + /* store the number of parameters on the stack,
1.1535 + * and store the native index as well.
1.1536 + */
1.1537 + cell_t native_index = jit->read_cell();
1.1538 + cell_t num_params = jit->read_cell();
1.1539 +
1.1540 + if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->info.natives_num)
1.1541 + {
1.1542 + ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM;
1.1543 + return;
1.1544 + }
1.1545 +
1.1546 + //mov eax, <num_params>
1.1547 + //mov ecx, <native_index>
1.1548 + IA32_Mov_Reg_Imm32(jit, REG_EAX, num_params);
1.1549 + IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index);
1.1550 +
1.1551 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1552 + IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_n);
1.1553 +}
1.1554 +
1.1555 +inline void WriteOp_Sysreq_N(JitWriter *jit)
1.1556 +{
1.1557 + /* The big daddy of opcodes. */
1.1558 + cell_t native_index = jit->read_cell();
1.1559 + cell_t num_params = jit->read_cell();
1.1560 + CompData *data = (CompData *)jit->data;
1.1561 +
1.1562 + if ((uint32_t)native_index >= data->plugin->info.natives_num)
1.1563 + {
1.1564 + data->error_set = SP_ERROR_INSTRUCTION_PARAM;
1.1565 + return;
1.1566 + }
1.1567 +
1.1568 + /* store the number of parameters on the stack */
1.1569 + //mov [edi-4], num_params
1.1570 + //sub edi, 4
1.1571 + IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4);
1.1572 + IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
1.1573 +
1.1574 + /* save registers we will need */
1.1575 + //push edx
1.1576 + IA32_Push_Reg(jit, AMX_REG_ALT);
1.1577 +
1.1578 + /* push some callback stuff */
1.1579 + //push edi ; stack
1.1580 + //push <native> ; native index
1.1581 + IA32_Push_Reg(jit, AMX_REG_STK);
1.1582 + if (native_index < SCHAR_MAX && native_index > SCHAR_MIN)
1.1583 + {
1.1584 + IA32_Push_Imm8(jit, (jit_int8_t)native_index);
1.1585 + } else {
1.1586 + IA32_Push_Imm32(jit, native_index);
1.1587 + }
1.1588 +
1.1589 + /* Relocate stack, heap, frm information, then store back */
1.1590 + //mov eax, [esi+context]
1.1591 + //mov ecx, [esi+hea]
1.1592 + //sub edi, ebp
1.1593 + //mov [eax+hp], ecx
1.1594 + //mov ecx, [esi]
1.1595 + //mov [eax+sp], edi
1.1596 + //mov [eax+frm], ecx
1.1597 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.1598 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
1.1599 + IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.1600 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
1.1601 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
1.1602 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
1.1603 + IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
1.1604 +
1.1605 + /* finally, push the last parameter and make the call */
1.1606 + //push eax ; context
1.1607 + //call NativeCallback
1.1608 + IA32_Push_Reg(jit, REG_EAX);
1.1609 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1610 + if (!data->debug)
1.1611 + {
1.1612 + IA32_Write_Jump32_Abs(jit, call, NativeCallback);
1.1613 + } else {
1.1614 + IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug);
1.1615 + }
1.1616 +
1.1617 + /* check for errors */
1.1618 + //mov ecx, [esi+context]
1.1619 + //cmp [ecx+err], 0
1.1620 + //jnz :error
1.1621 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.1622 + IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
1.1623 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
1.1624 +
1.1625 + /* restore what we damaged */
1.1626 + //add esp, 4*3
1.1627 + //add edi, ebp
1.1628 + //pop edx
1.1629 + IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
1.1630 + IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
1.1631 + IA32_Pop_Reg(jit, AMX_REG_ALT);
1.1632 +
1.1633 + /* pop the stack. do not check the margins.
1.1634 + * Note that this is not a true macro - we don't bother to
1.1635 + * set ALT here because nothing will be using it.
1.1636 + */
1.1637 + num_params++;
1.1638 + num_params *= 4;
1.1639 + //add edi, <val*4+4>
1.1640 + if (num_params < SCHAR_MAX && num_params > SCHAR_MIN)
1.1641 + {
1.1642 + IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG);
1.1643 + } else {
1.1644 + IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG);
1.1645 + }
1.1646 +}
1.1647 +
1.1648 +inline void WriteOp_Tracker_Push_C(JitWriter *jit)
1.1649 +{
1.1650 + CompData *data = (CompData *)jit->data;
1.1651 + cell_t val = jit->read_cell();
1.1652 +
1.1653 + /* Save registers that may be damaged by the call */
1.1654 + //push eax
1.1655 + //push edx
1.1656 + IA32_Push_Reg(jit, AMX_REG_PRI);
1.1657 + IA32_Push_Reg(jit, AMX_REG_ALT);
1.1658 +
1.1659 + /* Get the context ptr, push it and call the check */
1.1660 + //mov eax, [esi+context]
1.1661 + //push eax
1.1662 + //call JIT_VerifyOrAllocateTracker
1.1663 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.1664 + IA32_Push_Reg(jit, REG_EAX);
1.1665 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1666 + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
1.1667 +
1.1668 + /* Check for errors */
1.1669 + //pop eax
1.1670 + //cmp [eax+err], 0
1.1671 + //jnz :error
1.1672 + IA32_Pop_Reg(jit, REG_EAX);
1.1673 + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
1.1674 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
1.1675 +
1.1676 + /* Push the value into the stack and increment pCur */
1.1677 + //mov edx, [eax+vm[]]
1.1678 + //mov ecx, [edx+pcur]
1.1679 + //add [edx+pcur], 4
1.1680 + //mov [ecx], <val>*4 ; we want the count in bytes not in cells
1.1681 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
1.1682 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
1.1683 + IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
1.1684 + IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG);
1.1685 +
1.1686 + /* Restore PRI & ALT */
1.1687 + //pop edx
1.1688 + //pop eax
1.1689 + IA32_Pop_Reg(jit, AMX_REG_ALT);
1.1690 + IA32_Pop_Reg(jit, AMX_REG_PRI);
1.1691 +}
1.1692 +
1.1693 +inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit)
1.1694 +{
1.1695 + CompData *data = (CompData *)jit->data;
1.1696 +
1.1697 + /* Save registers that may be damaged by the call */
1.1698 + //push eax
1.1699 + //push edx
1.1700 + IA32_Push_Reg(jit, AMX_REG_PRI);
1.1701 + IA32_Push_Reg(jit, AMX_REG_ALT);
1.1702 +
1.1703 + /* Get the context ptr, push it and call the check */
1.1704 + //mov eax, [esi+context]
1.1705 + //push eax
1.1706 + //call JIT_VerifyLowBoundTracker
1.1707 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
1.1708 + IA32_Push_Reg(jit, REG_EAX);
1.1709 + jitoffs_t call = IA32_Call_Imm32(jit, 0);
1.1710 + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker);
1.1711 +
1.1712 + /* Check for errors */
1.1713 + //pop eax
1.1714 + //cmp [eax+err], 0
1.1715 + //jnz :error
1.1716 + IA32_Pop_Reg(jit, REG_EAX);
1.1717 + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
1.1718 + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
1.1719 +
1.1720 + /* Pop the value from the stack and decrease the heap by it*/
1.1721 + //mov edx, [eax+vm[]]
1.1722 + //sub [edx+pcur], 4
1.1723 + //mov ecx, [edx+pcur]
1.1724 + //mov ecx, [ecx]
1.1725 + //sub [esi+hea], ecx
1.1726 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
1.1727 + IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
1.1728 + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
1.1729 + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG);
1.1730 + IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP);
1.1731 +
1.1732 + Write_CheckHeap_Min(jit);
1.1733 +
1.1734 + /* Restore PRI & ALT */
1.1735 + //pop edx
1.1736 + //pop eax
1.1737 + IA32_Pop_Reg(jit, AMX_REG_ALT);
1.1738 + IA32_Pop_Reg(jit, AMX_REG_PRI);
1.1739 +}
1.1740 +
1.1741 +/*************************************************
1.1742 + *************************************************
1.1743 + * JIT PROPER ************************************
1.1744 + * The rest from now on is the JIT engine *
1.1745 + *************************************************
1.1746 + *************************************************/
1.1747 +
1.1748 +cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
1.1749 +{
1.1750 + sp_native_t *native = &ctx->natives[native_idx];
1.1751 +
1.1752 + /* Technically both aren't needed, I guess */
1.1753 + if (native->status == SP_NATIVE_NONE)
1.1754 + {
1.1755 + ctx->err = SP_ERROR_NATIVE_PENDING;
1.1756 + return 0;
1.1757 + }
1.1758 +
1.1759 + return native->pfn(ctx, params);
1.1760 +}
1.1761 +
1.1762 +cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
1.1763 +{
1.1764 + cell_t save_sp = ctx->sp;
1.1765 + cell_t save_hp = ctx->hp;
1.1766 +
1.1767 + if (ctx->hp < ctx->heap_base)
1.1768 + {
1.1769 + ctx->err = SP_ERROR_HEAPMIN;
1.1770 + return 0;
1.1771 + }
1.1772 +
1.1773 + if (ctx->hp + STACK_MARGIN > ctx->sp)
1.1774 + {
1.1775 + ctx->err = SP_ERROR_STACKLOW;
1.1776 + return 0;
1.1777 + }
1.1778 +
1.1779 + if ((uint32_t)ctx->sp >= ctx->mem_size)
1.1780 + {
1.1781 + ctx->err = SP_ERROR_STACKMIN;
1.1782 + return 0;
1.1783 + }
1.1784 +
1.1785 + cell_t result = NativeCallback(ctx, native_idx, params);
1.1786 +
1.1787 + if (ctx->err != SP_ERROR_NONE)
1.1788 + {
1.1789 + return result;
1.1790 + }
1.1791 +
1.1792 + if (save_sp != ctx->sp)
1.1793 + {
1.1794 + ctx->err = SP_ERROR_STACKLEAK;
1.1795 + return result;
1.1796 + } else if (save_hp != ctx->hp) {
1.1797 + ctx->err = SP_ERROR_HEAPLEAK;
1.1798 + return result;
1.1799 + }
1.1800 +
1.1801 + return result;
1.1802 +}
1.1803 +
1.1804 +jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
1.1805 +{
1.1806 + if (jit->outptr)
1.1807 + {
1.1808 + CompData *data = (CompData *)jit->data;
1.1809 + if (relative)
1.1810 + {
1.1811 + /* The actual offset is EIP relative. We need to relocate it.
1.1812 + * Note that this assumes that we're pointing to the next op.
1.1813 + */
1.1814 + pcode_offs += jit->get_inputpos();
1.1815 + }
1.1816 + /* Offset must always be 1)positive and 2)less than the codesize */
1.1817 + assert(pcode_offs >= 0 && (uint32_t)pcode_offs < data->codesize);
1.1818 + /* Do the lookup in the native dictionary. */
1.1819 + return *(jitoffs_t *)(data->rebase + pcode_offs);
1.1820 + } else {
1.1821 + return 0;
1.1822 + }
1.1823 +}
1.1824 +
1.1825 +void WriteErrorRoutines(CompData *data, JitWriter *jit)
1.1826 +{
1.1827 + data->jit_error_divzero = jit->get_outputpos();
1.1828 + Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO);
1.1829 +
1.1830 + data->jit_error_stacklow = jit->get_outputpos();
1.1831 + Write_SetError(jit, SP_ERROR_STACKLOW);
1.1832 +
1.1833 + data->jit_error_stackmin = jit->get_outputpos();
1.1834 + Write_SetError(jit, SP_ERROR_STACKMIN);
1.1835 +
1.1836 + data->jit_error_bounds = jit->get_outputpos();
1.1837 + Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS);
1.1838 +
1.1839 + data->jit_error_memaccess = jit->get_outputpos();
1.1840 + Write_SetError(jit, SP_ERROR_MEMACCESS);
1.1841 +
1.1842 + data->jit_error_heaplow = jit->get_outputpos();
1.1843 + Write_SetError(jit, SP_ERROR_HEAPLOW);
1.1844 +
1.1845 + data->jit_error_heapmin = jit->get_outputpos();
1.1846 + Write_SetError(jit, SP_ERROR_HEAPMIN);
1.1847 +
1.1848 + data->jit_error_array_too_big = jit->get_outputpos();
1.1849 + Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG);
1.1850 +
1.1851 + data->jit_error_tracker_bounds = jit->get_outputpos();
1.1852 + Write_SetError(jit, SP_ERROR_TRACKER_BOUNDS);
1.1853 +
1.1854 + data->jit_extern_error = jit->get_outputpos();
1.1855 + Write_GetError(jit);
1.1856 +}
1.1857 +
1.1858 +sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err)
1.1859 +{
1.1860 + CompData *data = (CompData *)co;
1.1861 + sp_plugin_t *plugin = data->plugin;
1.1862 +
1.1863 + /* The first phase is to browse */
1.1864 + uint8_t *code = plugin->pcode;
1.1865 + uint8_t *end_cip = plugin->pcode + plugin->pcode_size;
1.1866 + OPCODE op;
1.1867 +
1.1868 + /*********************************************
1.1869 + * FIRST PASS (medium load): writer.outbase is NULL, getting size only
1.1870 + * SECOND PASS (heavy load!!): writer.outbase is valid and output is written
1.1871 + *********************************************/
1.1872 +
1.1873 + JitWriter writer;
1.1874 + JitWriter *jit = &writer;
1.1875 + cell_t *endptr = (cell_t *)(end_cip);
1.1876 +
1.1877 + /* Initial code is written "blank,"
1.1878 + * so we can check the exact memory usage.
1.1879 + */
1.1880 + data->codesize = plugin->pcode_size;
1.1881 + writer.data = data;
1.1882 + writer.inbase = (cell_t *)code;
1.1883 + writer.outptr = NULL;
1.1884 + writer.outbase = NULL;
1.1885 + data->rebase = (jitcode_t)engine->BaseAlloc(plugin->pcode_size);
1.1886 +
1.1887 + /* We will jump back here for second pass */
1.1888 +jit_rewind:
1.1889 + /* Initialize pass vars */
1.1890 + writer.inptr = writer.inbase;
1.1891 + data->jit_verify_addr_eax = 0;
1.1892 + data->jit_verify_addr_edx = 0;
1.1893 +
1.1894 + /* Write the prologue of the JIT */
1.1895 + data->jit_return = Write_Execute_Function(jit);
1.1896 +
1.1897 + /* Write the SYSREQ.N opcode if we need to */
1.1898 + if (!(data->inline_level & JIT_INLINE_NATIVES))
1.1899 + {
1.1900 + data->jit_sysreq_n = jit->get_outputpos();
1.1901 + WriteOp_Sysreq_N_Function(jit);
1.1902 + }
1.1903 +
1.1904 + /* Plugins compiled with -O0 will need this! */
1.1905 + data->jit_sysreq_c = jit->get_outputpos();
1.1906 + WriteOp_Sysreq_C_Function(jit);
1.1907 +
1.1908 + data->jit_genarray = jit->get_outputpos();
1.1909 + WriteIntrinsic_GenArray(jit);
1.1910 +
1.1911 + /* Write error checking routines that are called to */
1.1912 + if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
1.1913 + {
1.1914 + data->jit_verify_addr_eax = jit->get_outputpos();
1.1915 + Write_Check_VerifyAddr(jit, REG_EAX);
1.1916 +
1.1917 + data->jit_verify_addr_edx = jit->get_outputpos();
1.1918 + Write_Check_VerifyAddr(jit, REG_EDX);
1.1919 + }
1.1920 +
1.1921 + /* Actual code generation! */
1.1922 + if (writer.outbase == NULL)
1.1923 + {
1.1924 + /* First Pass - find codesize and resolve relocation */
1.1925 + jitoffs_t pcode_offs;
1.1926 + jitoffs_t native_offs;
1.1927 +
1.1928 + for (; writer.inptr < endptr;)
1.1929 + {
1.1930 + /* Store the native offset into the rebase memory.
1.1931 + * This large chunk of memory lets us do an instant lookup
1.1932 + * based on an original pcode offset.
1.1933 + */
1.1934 + pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code);
1.1935 + native_offs = jit->get_outputpos();
1.1936 + *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs;
1.1937 +
1.1938 + /* Now read the opcode and continue. */
1.1939 + op = (OPCODE)writer.read_cell();
1.1940 + switch (op)
1.1941 + {
1.1942 + #include "opcode_switch.inc"
1.1943 + }
1.1944 + /* Check for errors. This should only happen in the first pass. */
1.1945 + if (data->error_set != SP_ERROR_NONE)
1.1946 + {
1.1947 + *err = data->error_set;
1.1948 + AbortCompilation(co);
1.1949 + return NULL;
1.1950 + }
1.1951 + }
1.1952 + /* Write these last because error jumps should be unpredicted, and thus forward */
1.1953 + WriteErrorRoutines(data, jit);
1.1954 +
1.1955 + /* the total codesize is now known! */
1.1956 + uint32_t mem = writer.get_outputpos();
1.1957 + writer.outbase = (jitcode_t)engine->ExecAlloc(mem);
1.1958 + writer.outptr = writer.outbase;
1.1959 + /* go back for third pass */
1.1960 + goto jit_rewind;
1.1961 + } else {
1.1962 + /*******
1.1963 + * THIRD PASS - write opcode info
1.1964 + *******/
1.1965 + for (; writer.inptr < endptr;)
1.1966 + {
1.1967 + op = (OPCODE)writer.read_cell();
1.1968 + switch (op)
1.1969 + {
1.1970 + #include "opcode_switch.inc"
1.1971 + }
1.1972 + }
1.1973 + /* Write these last because error jumps should be unpredicted, and thus forward */
1.1974 + WriteErrorRoutines(data, jit);
1.1975 + }
1.1976 +
1.1977 + /*************
1.1978 + * FOURTH PASS - Context Setup
1.1979 + *************/
1.1980 +
1.1981 + sp_context_t *ctx = new sp_context_t;
1.1982 + memset(ctx, 0, sizeof(sp_context_t));
1.1983 +
1.1984 + /* setup basics */
1.1985 + ctx->codebase = writer.outbase;
1.1986 + ctx->plugin = plugin;
1.1987 + ctx->vmbase = this;
1.1988 + ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0);
1.1989 +
1.1990 + /* setup memory */
1.1991 + ctx->memory = new uint8_t[plugin->memory];
1.1992 + memcpy(ctx->memory, plugin->data, plugin->data_size);
1.1993 + ctx->mem_size = plugin->memory;
1.1994 + ctx->heap_base = plugin->data_size;
1.1995 + ctx->hp = ctx->heap_base;
1.1996 + ctx->sp = ctx->mem_size - sizeof(cell_t);
1.1997 +
1.1998 + const char *strbase = plugin->info.stringbase;
1.1999 + uint32_t max, iter;
1.2000 +
1.2001 + /* relocate public info */
1.2002 + if ((max = plugin->info.publics_num))
1.2003 + {
1.2004 + ctx->publics = new sp_public_t[max];
1.2005 + for (iter=0; iter<max; iter++)
1.2006 + {
1.2007 + ctx->publics[iter].name = strbase + plugin->info.publics[iter].name;
1.2008 + ctx->publics[iter].offs = RelocLookup(jit, plugin->info.publics[iter].address, false);
1.2009 + }
1.2010 + }
1.2011 +
1.2012 + /* relocate pubvar info */
1.2013 + if ((max = plugin->info.pubvars_num))
1.2014 + {
1.2015 + uint8_t *dat = ctx->memory;
1.2016 + ctx->pubvars = new sp_pubvar_t[max];
1.2017 + for (iter=0; iter<max; iter++)
1.2018 + {
1.2019 + ctx->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name;
1.2020 + ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address);
1.2021 + }
1.2022 + }
1.2023 +
1.2024 + /* relocate native info */
1.2025 + if ((max = plugin->info.natives_num))
1.2026 + {
1.2027 + ctx->natives = new sp_native_t[max];
1.2028 + for (iter=0; iter<max; iter++)
1.2029 + {
1.2030 + ctx->natives[iter].name = strbase + plugin->info.natives[iter].name;
1.2031 + ctx->natives[iter].pfn = NULL;
1.2032 + ctx->natives[iter].status = SP_NATIVE_NONE;
1.2033 + }
1.2034 + }
1.2035 +
1.2036 + /**
1.2037 + * If we're debugging, make sure we copy the necessary info.
1.2038 + */
1.2039 + if (data->debug)
1.2040 + {
1.2041 + strbase = plugin->debug.stringbase;
1.2042 +
1.2043 + /* relocate files */
1.2044 + max = plugin->debug.files_num;
1.2045 + ctx->files = new sp_debug_file_t[max];
1.2046 + for (iter=0; iter<max; iter++)
1.2047 + {
1.2048 + ctx->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false);
1.2049 + ctx->files[iter].name = strbase + plugin->debug.files[iter].name;
1.2050 + }
1.2051 +
1.2052 + /* relocate lines */
1.2053 + max = plugin->debug.lines_num;
1.2054 + ctx->lines = new sp_debug_line_t[max];
1.2055 + for (iter=0; iter<max; iter++)
1.2056 + {
1.2057 + ctx->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false);
1.2058 + ctx->lines[iter].line = plugin->debug.lines[iter].line;
1.2059 + }
1.2060 +
1.2061 + /* relocate arrays */
1.2062 + sp_fdbg_symbol_t *sym;
1.2063 + sp_fdbg_arraydim_t *arr;
1.2064 + uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
1.2065 +
1.2066 + max = plugin->debug.syms_num;
1.2067 + ctx->symbols = new sp_debug_symbol_t[max];
1.2068 + for (iter=0; iter<max; iter++)
1.2069 + {
1.2070 + sym = (sp_fdbg_symbol_t *)cursor;
1.2071 +
1.2072 + ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false);
1.2073 + ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false);
1.2074 + ctx->symbols[iter].name = strbase + sym->name;
1.2075 + ctx->symbols[iter].sym = sym;
1.2076 +
1.2077 + if (sym->dimcount > 0)
1.2078 + {
1.2079 + cursor += sizeof(sp_fdbg_symbol_t);
1.2080 + arr = (sp_fdbg_arraydim_t *)cursor;
1.2081 + ctx->symbols[iter].dims = arr;
1.2082 + cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
1.2083 + continue;
1.2084 + }
1.2085 +
1.2086 + ctx->symbols[iter].dims = NULL;
1.2087 + cursor += sizeof(sp_fdbg_symbol_t);
1.2088 + }
1.2089 + }
1.2090 +
1.2091 + tracker_t *trk = new tracker_t;
1.2092 + ctx->vm[JITVARS_TRACKER] = trk;
1.2093 + trk->pBase = (ucell_t *)malloc(1024);
1.2094 + trk->pCur = trk->pBase;
1.2095 + trk->size = 1024 / sizeof(cell_t);
1.2096 +
1.2097 + /* clean up relocation+compilation memory */
1.2098 + AbortCompilation(co);
1.2099 +
1.2100 + *err = SP_ERROR_NONE;
1.2101 +
1.2102 + return ctx;
1.2103 +}
1.2104 +
1.2105 +const char *JITX86::GetVMName()
1.2106 +{
1.2107 + return "JIT (x86)";
1.2108 +}
1.2109 +
1.2110 +int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result)
1.2111 +{
1.2112 + typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *);
1.2113 + CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase;
1.2114 + return fn(ctx, code_idx, result);
1.2115 +}
1.2116 +
1.2117 +void JITX86::FreeContext(sp_context_t *ctx)
1.2118 +{
1.2119 + engine->ExecFree(ctx->codebase);
1.2120 + delete [] ctx->memory;
1.2121 + delete [] ctx->files;
1.2122 + delete [] ctx->lines;
1.2123 + delete [] ctx->natives;
1.2124 + delete [] ctx->publics;
1.2125 + delete [] ctx->pubvars;
1.2126 + delete [] ctx->symbols;
1.2127 + free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
1.2128 + delete ctx->vm[JITVARS_TRACKER];
1.2129 + delete ctx;
1.2130 +}
1.2131 +
1.2132 +ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin)
1.2133 +{
1.2134 + CompData *data = new CompData;
1.2135 +
1.2136 + data->plugin = plugin;
1.2137 + data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
1.2138 + data->error_set = SP_ERROR_NONE;
1.2139 +
1.2140 + return data;
1.2141 +}
1.2142 +
1.2143 +void JITX86::AbortCompilation(ICompilation *co)
1.2144 +{
1.2145 + if (((CompData *)co)->rebase)
1.2146 + {
1.2147 + engine->BaseFree(((CompData *)co)->rebase);
1.2148 + }
1.2149 + delete (CompData *)co;
1.2150 +}
1.2151 +
1.2152 +bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char *val)
1.2153 +{
1.2154 + CompData *data = (CompData *)co;
1.2155 +
1.2156 + if (strcmp(key, "debug") == 0)
1.2157 + {
1.2158 + data->debug = (atoi(val) == 1);
1.2159 + if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG))
1.2160 + {
1.2161 + data->debug = false;
1.2162 + return false;
1.2163 + }
1.2164 + return true;
1.2165 + }
1.2166 +
1.2167 + return false;
1.2168 +}