sourcepawn/jit/x86/jit_x86.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 15 05:22:26 2008 +0000 (2008-08-15)
changeset 2226 d10b38524be3
parent 2195 5b70179559f9
child 2231 f13eb5a31226
permissions -rw-r--r--
Landed sourcepawn-1.2. The big changes:

1) JIT compilation/optimization now occurs per-function, and only when functions are first used. We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT). This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive. If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.

2) I've removed debug mode. We always show full backtraces now, as there was a very cheap way to implement this which really cleaned up everything. This is great for a number of reasons -- there's less code, the JIT is better designed, we don't need to relocate debug tables, and best of all we no longer have to tell users to enable debug mode at their own expense.
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
dvander@2114
     4
 * SourceMod
dvander@2114
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
dvander@2114
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2114
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2114
    10
 * Free Software Foundation.
dvander@2114
    11
 * 
dvander@2114
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2114
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2114
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2114
    15
 * details.
dvander@2114
    16
 *
dvander@2114
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2114
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2114
    19
 *
dvander@2114
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2114
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2114
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2114
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2114
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2114
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2114
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2114
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <string.h>
ds@1952
    33
#include <stdlib.h>
ds@1952
    34
#include <assert.h>
ds@1952
    35
#include "jit_x86.h"
ds@1952
    36
#include "opcode_helpers.h"
ds@1952
    37
#include <x86_macros.h>
dvander@2193
    38
#include "../jit_version.h"
dvander@2193
    39
#include "../sp_vm_engine.h"
dvander@2193
    40
#include "../engine2.h"
dvander@2193
    41
#include "../BaseRuntime.h"
dvander@2193
    42
#include "../sp_vm_basecontext.h"
ds@1952
    43
dvander@2226
    44
using namespace Knight;
dvander@2226
    45
ds@1952
    46
#if defined USE_UNGEN_OPCODES
ds@1952
    47
#include "ungen_opcodes.h"
ds@1952
    48
#endif
ds@1952
    49
dvander@2226
    50
JITX86 g_Jit;
dvander@2226
    51
KeCodeCache *g_pCodeCache = NULL;
dvander@2193
    52
ISourcePawnEngine *engine = &g_engine1;
dvander@2193
    53
dvander@2193
    54
inline sp_plugin_t *GETPLUGIN(sp_context_t *ctx)
dvander@2193
    55
{
dvander@2193
    56
	return (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]);
dvander@2193
    57
}
dvander@2193
    58
ds@1952
    59
inline void WriteOp_Move_Pri(JitWriter *jit)
ds@1952
    60
{
ds@1952
    61
	//mov eax, edx
ds@1952
    62
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
    63
}
ds@1952
    64
ds@1952
    65
inline void WriteOp_Move_Alt(JitWriter *jit)
ds@1952
    66
{
ds@1952
    67
	//mov edx, eax
ds@1952
    68
	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
ds@1952
    69
}
ds@1952
    70
ds@1952
    71
inline void WriteOp_Xchg(JitWriter *jit)
ds@1952
    72
{
ds@1952
    73
	//xchg eax, edx
ds@1952
    74
	IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT);
ds@1952
    75
}
ds@1952
    76
ds@1952
    77
inline void WriteOp_Push(JitWriter *jit)
ds@1952
    78
{
ds@1952
    79
	//push stack, DAT offset based
ds@1952
    80
	//sub edi, 4
ds@1952
    81
	//mov ecx, [ebp+<val>]
ds@1952
    82
	//mov [edi], ecx
ds@1952
    83
	cell_t val = jit->read_cell();
ds@1952
    84
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
    85
	//optimize encoding a bit...
faluco@2029
    86
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
    87
	{
ds@1952
    88
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
    89
	} else {
ds@1952
    90
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
ds@1952
    91
	}
ds@1952
    92
	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
    93
}
ds@1952
    94
ds@1952
    95
inline void WriteOp_Push_C(JitWriter *jit)
ds@1952
    96
{
ds@1952
    97
	//push stack
ds@1952
    98
	//mov [edi-4], <val>
ds@1952
    99
	//sub edi, 4
ds@1952
   100
	cell_t val = jit->read_cell();
ds@1952
   101
	IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4);
ds@1952
   102
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   103
}
ds@1952
   104
ds@1952
   105
inline void WriteOp_Zero(JitWriter *jit)
ds@1952
   106
{
ds@1952
   107
	//mov [ebp+<val>], 0
ds@1952
   108
	cell_t val = jit->read_cell();
faluco@2029
   109
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   110
	{
ds@1952
   111
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val);
ds@1952
   112
	} else {
ds@1952
   113
		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val);
ds@1952
   114
	}
ds@1952
   115
}
ds@1952
   116
ds@1952
   117
inline void WriteOp_Zero_S(JitWriter *jit)
ds@1952
   118
{
ds@1952
   119
	//mov [ebx+<val>], 0
ds@1952
   120
	cell_t val = jit->read_cell();
faluco@2029
   121
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   122
	{
ds@1952
   123
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val);
ds@1952
   124
	} else {
ds@1952
   125
		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val);
ds@1952
   126
	}
ds@1952
   127
}
ds@1952
   128
ds@1952
   129
inline void WriteOp_Push_S(JitWriter *jit)
ds@1952
   130
{
ds@1952
   131
	//push stack, FRM offset based
ds@1952
   132
	//sub edi, 4
ds@1952
   133
	//mov ecx, [ebx+<val>]
ds@1952
   134
	//mov [edi], ecx
ds@1952
   135
	cell_t val = jit->read_cell();
ds@1952
   136
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   137
	//optimize encoding a bit...
faluco@2029
   138
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   139
	{
ds@1952
   140
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   141
	} else {
ds@1952
   142
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
ds@1952
   143
	}
ds@1952
   144
	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
   145
}
ds@1952
   146
ds@1952
   147
inline void WriteOp_Push_Pri(JitWriter *jit)
ds@1952
   148
{
ds@1952
   149
	//mov [edi-4], eax
ds@1952
   150
	//sub edi, 4
ds@1952
   151
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4);
ds@1952
   152
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   153
}
ds@1952
   154
ds@1952
   155
inline void WriteOp_Push_Alt(JitWriter *jit)
ds@1952
   156
{
ds@1952
   157
	//mov [edi-4], edx
ds@1952
   158
	//sub edi, 4
ds@1952
   159
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4);
ds@1952
   160
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   161
}
ds@1952
   162
ds@1952
   163
inline void WriteOp_Push2_C(JitWriter *jit)
ds@1952
   164
{
ds@1952
   165
	Macro_PushN_C(jit, 2);
ds@1952
   166
}
ds@1952
   167
ds@1952
   168
inline void WriteOp_Push3_C(JitWriter *jit)
ds@1952
   169
{
ds@1952
   170
	Macro_PushN_C(jit, 3);
ds@1952
   171
}
ds@1952
   172
ds@1952
   173
inline void WriteOp_Push4_C(JitWriter *jit)
ds@1952
   174
{
ds@1952
   175
	Macro_PushN_C(jit, 4);
ds@1952
   176
}
ds@1952
   177
ds@1952
   178
inline void WriteOp_Push5_C(JitWriter *jit)
ds@1952
   179
{
ds@1952
   180
	Macro_PushN_C(jit, 5);
ds@1952
   181
}
ds@1952
   182
ds@1952
   183
inline void WriteOp_Push2_Adr(JitWriter *jit)
ds@1952
   184
{
ds@1952
   185
	Macro_PushN_Addr(jit, 2);
ds@1952
   186
}
ds@1952
   187
ds@1952
   188
inline void WriteOp_Push3_Adr(JitWriter *jit)
ds@1952
   189
{
ds@1952
   190
	Macro_PushN_Addr(jit, 3);
ds@1952
   191
}
ds@1952
   192
ds@1952
   193
inline void WriteOp_Push4_Adr(JitWriter *jit)
ds@1952
   194
{
ds@1952
   195
	Macro_PushN_Addr(jit, 4);
ds@1952
   196
}
ds@1952
   197
ds@1952
   198
inline void WriteOp_Push5_Adr(JitWriter *jit)
ds@1952
   199
{
ds@1952
   200
	Macro_PushN_Addr(jit, 5);
ds@1952
   201
}
ds@1952
   202
ds@1952
   203
inline void WriteOp_Push2_S(JitWriter *jit)
ds@1952
   204
{
ds@1952
   205
	Macro_PushN_S(jit, 2);
ds@1952
   206
}
ds@1952
   207
ds@1952
   208
inline void WriteOp_Push3_S(JitWriter *jit)
ds@1952
   209
{
ds@1952
   210
	Macro_PushN_S(jit, 3);
ds@1952
   211
}
ds@1952
   212
ds@1952
   213
inline void WriteOp_Push4_S(JitWriter *jit)
ds@1952
   214
{
ds@1952
   215
	Macro_PushN_S(jit, 4);
ds@1952
   216
}
ds@1952
   217
ds@1952
   218
inline void WriteOp_Push5_S(JitWriter *jit)
ds@1952
   219
{
ds@1952
   220
	Macro_PushN_S(jit, 5);
ds@1952
   221
}
ds@1952
   222
ds@1952
   223
inline void WriteOp_Push5(JitWriter *jit)
ds@1952
   224
{
ds@1952
   225
	Macro_PushN(jit, 5);
ds@1952
   226
}
ds@1952
   227
ds@1952
   228
inline void WriteOp_Push4(JitWriter *jit)
ds@1952
   229
{
ds@1952
   230
	Macro_PushN(jit, 4);
ds@1952
   231
}
ds@1952
   232
ds@1952
   233
inline void WriteOp_Push3(JitWriter *jit)
ds@1952
   234
{
ds@1952
   235
	Macro_PushN(jit, 3);
ds@1952
   236
}
ds@1952
   237
ds@1952
   238
inline void WriteOp_Push2(JitWriter *jit)
ds@1952
   239
{
ds@1952
   240
	Macro_PushN(jit, 2);
ds@1952
   241
}
ds@1952
   242
ds@1952
   243
inline void WriteOp_Zero_Pri(JitWriter *jit)
ds@1952
   244
{
ds@1952
   245
	//xor eax, eax
ds@1952
   246
	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
ds@1952
   247
}
ds@1952
   248
ds@1952
   249
inline void WriteOp_Zero_Alt(JitWriter *jit)
ds@1952
   250
{
ds@1952
   251
	//xor edx, edx
ds@1952
   252
	IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
ds@1952
   253
}
ds@1952
   254
ds@1952
   255
inline void WriteOp_Add(JitWriter *jit)
ds@1952
   256
{
ds@1952
   257
	//add eax, edx
ds@1952
   258
	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   259
}
ds@1952
   260
ds@1952
   261
inline void WriteOp_Sub(JitWriter *jit)
ds@1952
   262
{
ds@1952
   263
	//sub eax, edx
ds@1952
   264
	IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   265
}
ds@1952
   266
ds@1952
   267
inline void WriteOp_Sub_Alt(JitWriter *jit)
ds@1952
   268
{
ds@1952
   269
	//neg eax
ds@1952
   270
	//add eax, edx
ds@1952
   271
	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   272
	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   273
}
ds@1952
   274
ds@1952
   275
inline void WriteOp_Proc(JitWriter *jit)
ds@1952
   276
{
dvander@2226
   277
#if 0 /* :TODO: We no longer use this */
ds@1952
   278
	/* Specialized code to align this taking in account the function magic number */
ds@1952
   279
	jitoffs_t cur_offs = jit->get_outputpos();
ds@1952
   280
	jitoffs_t offset = ((cur_offs & 0xFFFFFFF8) + 8) - cur_offs;
ds@1952
   281
	if (!((offset + cur_offs) & 8))
ds@1952
   282
	{
ds@1952
   283
		offset += 8;
ds@1952
   284
	}
ds@1952
   285
	if (offset)
ds@1952
   286
	{
ds@1952
   287
		for (jit_uint32_t i=0; i<offset; i++)
ds@1952
   288
		{
ds@1952
   289
			jit->write_ubyte(IA32_INT3);
ds@1952
   290
		}
ds@1952
   291
	}
ds@1952
   292
ds@1952
   293
	/* Write the info struct about this function */
ds@1952
   294
	jit->write_uint32(JIT_FUNCMAGIC);
ds@1952
   295
	jit->write_uint32(co->func_idx);
ds@1952
   296
ds@1952
   297
	/* Now we have to backpatch our reloction offset! */
ds@1952
   298
	{
ds@1952
   299
		jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t);
dvander@2226
   300
		uint8_t *rebase = ((CompData *)jit->data)->rebase;
dvander@2226
   301
		*(jitoffs_t *)(rebase + offs) = jit->get_outputpos();
ds@1952
   302
	}
ds@1952
   303
ds@1952
   304
	/* Lastly, if we're writing, keep track of the function count */
ds@1952
   305
	if (jit->outbase)
ds@1952
   306
	{
ds@1952
   307
		co->func_idx++;
ds@1952
   308
	}
dvander@2226
   309
#endif
ds@1952
   310
ds@1952
   311
	//push old frame on stack:
ds@1952
   312
	//mov ecx, [esi+frm]
ds@1952
   313
	//mov [edi-4], ecx
ds@1952
   314
	//sub edi, 8			;extra un-used slot for non-existant CIP
ds@1952
   315
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
ds@1952
   316
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4);
ds@1952
   317
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
dvander@2226
   318
ds@1952
   319
	//save frame:
ds@1952
   320
	//mov ecx, edi			- get new frame
ds@1952
   321
	//mov ebx, edi			- store frame back
ds@1952
   322
	//sub ecx, ebp			- relocate local frame
ds@1952
   323
	//mov [esi+frm], ecx
ds@1952
   324
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
ds@1952
   325
	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
ds@1952
   326
	IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
ds@1952
   327
	IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
   328
}
ds@1952
   329
ds@1952
   330
inline void WriteOp_Lidx_B(JitWriter *jit)
ds@1952
   331
{
ds@1952
   332
	cell_t val = jit->read_cell();
ds@1952
   333
	//shl eax, <val>
ds@1952
   334
	//add eax, edx
ds@1952
   335
	//mov eax, [ebp+eax]
ds@1952
   336
	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
ds@1952
   337
	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   338
	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
ds@1952
   339
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
   340
}
ds@1952
   341
ds@1952
   342
inline void WriteOp_Idxaddr_B(JitWriter *jit)
ds@1952
   343
{
ds@1952
   344
	//shl eax, <val>
ds@1952
   345
	//add eax, edx
ds@1952
   346
	cell_t val = jit->read_cell();
ds@1952
   347
	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG);
ds@1952
   348
	IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   349
}
ds@1952
   350
ds@1952
   351
inline void WriteOp_Shl(JitWriter *jit)
ds@1952
   352
{
ds@1952
   353
	//mov ecx, edx
ds@1952
   354
	//shl eax, cl
ds@1952
   355
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
ds@1952
   356
	IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   357
}
ds@1952
   358
ds@1952
   359
inline void WriteOp_Shr(JitWriter *jit)
ds@1952
   360
{
ds@1952
   361
	//mov ecx, edx
ds@1952
   362
	//shr eax, cl
ds@1952
   363
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
ds@1952
   364
	IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   365
}
ds@1952
   366
ds@1952
   367
inline void WriteOp_Sshr(JitWriter *jit)
ds@1952
   368
{
ds@1952
   369
	//mov ecx, edx
ds@1952
   370
	//sar eax, cl
ds@1952
   371
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
ds@1952
   372
	IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   373
}
ds@1952
   374
ds@1952
   375
inline void WriteOp_Shl_C_Pri(JitWriter *jit)
ds@1952
   376
{
ds@1952
   377
	//shl eax, <val>
ds@1952
   378
	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
ds@1952
   379
	if (val == 1)
ds@1952
   380
	{
ds@1952
   381
		IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   382
	} else {
ds@1952
   383
		IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
ds@1952
   384
	}
ds@1952
   385
}
ds@1952
   386
ds@1952
   387
inline void WriteOp_Shl_C_Alt(JitWriter *jit)
ds@1952
   388
{
ds@1952
   389
	//shl edx, <val>
ds@1952
   390
	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
ds@1952
   391
	if (val == 1)
ds@1952
   392
	{
ds@1952
   393
		IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG);
ds@1952
   394
	} else {
ds@1952
   395
		IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
ds@1952
   396
	}
ds@1952
   397
}
ds@1952
   398
ds@1952
   399
inline void WriteOp_Shr_C_Pri(JitWriter *jit)
ds@1952
   400
{
ds@1952
   401
	//shr eax, <val>
ds@1952
   402
	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
ds@1952
   403
	if (val == 1)
ds@1952
   404
	{
ds@1952
   405
		IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   406
	} else {
ds@1952
   407
		IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG);
ds@1952
   408
	}
ds@1952
   409
}
ds@1952
   410
ds@1952
   411
inline void WriteOp_Shr_C_Alt(JitWriter *jit)
ds@1952
   412
{
ds@1952
   413
	//shr edx, <val>
ds@1952
   414
	jit_uint8_t val = (jit_uint8_t)jit->read_cell();
ds@1952
   415
	if (val == 1)
ds@1952
   416
	{
ds@1952
   417
		IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG);
ds@1952
   418
	} else {
ds@1952
   419
		IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG);
ds@1952
   420
	}
ds@1952
   421
}
ds@1952
   422
ds@1952
   423
inline void WriteOp_SMul(JitWriter *jit)
ds@1952
   424
{
ds@1952
   425
	//mov ecx, edx
ds@1952
   426
	//imul edx
ds@1952
   427
	//mov edx, ecx
ds@1952
   428
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
ds@1952
   429
	IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG);
ds@1952
   430
	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
ds@1952
   431
}
ds@1952
   432
ds@1952
   433
inline void WriteOp_Not(JitWriter *jit)
ds@1952
   434
{
ds@1952
   435
	//test eax, eax
ds@1952
   436
	//mov eax, 0
ds@1952
   437
	//sete al
ds@1952
   438
	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
ds@1952
   439
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   440
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
ds@1952
   441
}
ds@1952
   442
ds@1952
   443
inline void WriteOp_Neg(JitWriter *jit)
ds@1952
   444
{
ds@1952
   445
	//neg eax
ds@1952
   446
	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   447
}
ds@1952
   448
ds@1952
   449
inline void WriteOp_Xor(JitWriter *jit)
ds@1952
   450
{
ds@1952
   451
	//xor eax, edx
ds@1952
   452
	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   453
}
ds@1952
   454
ds@1952
   455
inline void WriteOp_Or(JitWriter *jit)
ds@1952
   456
{
ds@1952
   457
	//or eax, edx
ds@1952
   458
	IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   459
}
ds@1952
   460
ds@1952
   461
inline void WriteOp_And(JitWriter *jit)
ds@1952
   462
{
ds@1952
   463
	//and eax, edx
ds@1952
   464
	IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   465
}
ds@1952
   466
ds@1952
   467
inline void WriteOp_Invert(JitWriter *jit)
ds@1952
   468
{
ds@1952
   469
	//not eax
ds@1952
   470
	IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   471
}
ds@1952
   472
ds@1952
   473
inline void WriteOp_Add_C(JitWriter *jit)
ds@1952
   474
{
ds@1952
   475
	//add eax, <val>
ds@1952
   476
	cell_t val = jit->read_cell();
faluco@2029
   477
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   478
		IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
ds@1952
   479
	else
ds@1952
   480
		IA32_Add_Eax_Imm32(jit, val);
ds@1952
   481
}
ds@1952
   482
ds@1952
   483
inline void WriteOp_SMul_C(JitWriter *jit)
ds@1952
   484
{
ds@1952
   485
	//imul eax, <val>
ds@1952
   486
	cell_t val = jit->read_cell();
faluco@2029
   487
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   488
		IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
ds@1952
   489
	else
ds@1952
   490
		IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val);
ds@1952
   491
}
ds@1952
   492
ds@1952
   493
inline void WriteOp_Sign_Pri(JitWriter *jit)
ds@1952
   494
{
ds@1952
   495
	//shl eax, 24
ds@1952
   496
	//sar eax, 24
ds@1952
   497
	IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
ds@1952
   498
	IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG);
ds@1952
   499
}
ds@1952
   500
ds@1952
   501
inline void WriteOp_Sign_Alt(JitWriter *jit)
ds@1952
   502
{
ds@1952
   503
	//shl edx, 24
ds@1952
   504
	//sar edx, 24
ds@1952
   505
	IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
ds@1952
   506
	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG);
ds@1952
   507
}
ds@1952
   508
ds@1952
   509
inline void WriteOp_Eq(JitWriter *jit)
ds@1952
   510
{
ds@1952
   511
	//cmp eax, edx	; PRI == ALT ?
ds@1952
   512
	//mov eax, 0
ds@1952
   513
	//sete al
ds@1952
   514
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   515
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   516
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
ds@1952
   517
}
ds@1952
   518
ds@1952
   519
inline void WriteOp_Neq(JitWriter *jit)
ds@1952
   520
{
ds@1952
   521
	//cmp eax, edx	; PRI != ALT ?
ds@1952
   522
	//mov eax, 0
ds@1952
   523
	//setne al
ds@1952
   524
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   525
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   526
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_NE);
ds@1952
   527
}
ds@1952
   528
ds@1952
   529
inline void WriteOp_Sless(JitWriter *jit)
ds@1952
   530
{
ds@1952
   531
	//cmp eax, edx	; PRI < ALT ? (signed)
ds@1952
   532
	//mov eax, 0
ds@1952
   533
	//setl al
ds@1952
   534
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   535
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   536
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_L);
ds@1952
   537
}
ds@1952
   538
ds@1952
   539
inline void WriteOp_Sleq(JitWriter *jit)
ds@1952
   540
{
ds@1952
   541
	//cmp eax, edx	; PRI <= ALT ? (signed)
ds@1952
   542
	//mov eax, 0
ds@1952
   543
	//setle al
ds@1952
   544
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   545
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   546
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_LE);
ds@1952
   547
}
ds@1952
   548
ds@1952
   549
inline void WriteOp_Sgrtr(JitWriter *jit)
ds@1952
   550
{
ds@1952
   551
	//cmp eax, edx	; PRI > ALT ? (signed)
ds@1952
   552
	//mov eax, 0
ds@1952
   553
	//setg al
ds@1952
   554
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   555
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   556
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_G);
ds@1952
   557
}
ds@1952
   558
ds@1952
   559
inline void WriteOp_Sgeq(JitWriter *jit)
ds@1952
   560
{
ds@1952
   561
	//cmp eax, edx	; PRI >= ALT ? (signed)
ds@1952
   562
	//mov eax, 0
ds@1952
   563
	//setge al
ds@1952
   564
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
   565
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   566
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_GE);
ds@1952
   567
}
ds@1952
   568
ds@1952
   569
inline void WriteOp_Eq_C_Pri(JitWriter *jit)
ds@1952
   570
{
ds@1952
   571
	//cmp eax, <val>   ; PRI == value ?
ds@1952
   572
	//mov eax, 0
ds@1952
   573
	//sete al
ds@1952
   574
	cell_t val = jit->read_cell();
faluco@2029
   575
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   576
		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
ds@1952
   577
	else
ds@1952
   578
		IA32_Cmp_Eax_Imm32(jit, val);
ds@1952
   579
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
ds@1952
   580
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
ds@1952
   581
}
ds@1952
   582
ds@1952
   583
inline void WriteOp_Eq_C_Alt(JitWriter *jit)
ds@1952
   584
{
ds@1952
   585
	//xor eax, eax
ds@1952
   586
	//cmp edx, <val>   ; ALT == value ?
ds@1952
   587
	//sete al
ds@1952
   588
	cell_t val = jit->read_cell();
ds@1952
   589
	IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
faluco@2029
   590
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   591
		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val);
ds@1952
   592
	else
ds@1952
   593
		IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val);
ds@1952
   594
	IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E);
ds@1952
   595
}
ds@1952
   596
ds@1952
   597
inline void WriteOp_Inc_Pri(JitWriter *jit)
ds@1952
   598
{
ds@1952
   599
	//add eax, 1
ds@1952
   600
	IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
ds@1952
   601
}
ds@1952
   602
ds@1952
   603
inline void WriteOp_Inc_Alt(JitWriter *jit)
ds@1952
   604
{
ds@1952
   605
	//add edx, 1
ds@1952
   606
	IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
ds@1952
   607
}
ds@1952
   608
ds@1952
   609
inline void WriteOp_Inc(JitWriter *jit)
ds@1952
   610
{
ds@1952
   611
	//add [ebp+<val>], 1
ds@1952
   612
	cell_t val = jit->read_cell();
faluco@2029
   613
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   614
		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
ds@1952
   615
	else
ds@1952
   616
		IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
ds@1952
   617
}
ds@1952
   618
ds@1952
   619
inline void WriteOp_Inc_S(JitWriter *jit)
ds@1952
   620
{
ds@1952
   621
	//add [ebx+<val>], 1
ds@1952
   622
	cell_t val = jit->read_cell();
faluco@2029
   623
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   624
		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
ds@1952
   625
	else
ds@1952
   626
		IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
ds@1952
   627
}
ds@1952
   628
ds@1952
   629
inline void WriteOp_Inc_I(JitWriter *jit)
ds@1952
   630
{
ds@1952
   631
	//add [ebp+eax], 1
ds@1952
   632
	IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
ds@1952
   633
}
ds@1952
   634
ds@1952
   635
inline void WriteOp_Dec_Pri(JitWriter *jit)
ds@1952
   636
{
ds@1952
   637
	//sub eax, 1
ds@1952
   638
	IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG);
ds@1952
   639
}
ds@1952
   640
ds@1952
   641
inline void WriteOp_Dec_Alt(JitWriter *jit)
ds@1952
   642
{
ds@1952
   643
	//sub edx, 1
ds@1952
   644
	IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG);
ds@1952
   645
}
ds@1952
   646
ds@1952
   647
inline void WriteOp_Dec(JitWriter *jit)
ds@1952
   648
{
ds@1952
   649
	//sub [ebp+<val>], 1
ds@1952
   650
	cell_t val = jit->read_cell();
faluco@2029
   651
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   652
	{
ds@1952
   653
		IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val);
ds@1952
   654
	} else {
ds@1952
   655
		IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val);
ds@1952
   656
	}
ds@1952
   657
}
ds@1952
   658
ds@1952
   659
inline void WriteOp_Dec_S(JitWriter *jit)
ds@1952
   660
{
ds@1952
   661
	//sub [ebx+<val>], 1
ds@1952
   662
	cell_t val = jit->read_cell();
faluco@2029
   663
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   664
	{
ds@1952
   665
		IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val);
ds@1952
   666
	} else {
ds@1952
   667
		IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val);
ds@1952
   668
	}
ds@1952
   669
}
ds@1952
   670
ds@1952
   671
inline void WriteOp_Dec_I(JitWriter *jit)
ds@1952
   672
{
ds@1952
   673
	//sub [ebp+eax], 1
ds@1952
   674
	IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1);
ds@1952
   675
}
ds@1952
   676
ds@1952
   677
inline void WriteOp_Load_Pri(JitWriter *jit)
ds@1952
   678
{
ds@1952
   679
	//mov eax, [ebp+<val>]
ds@1952
   680
	cell_t val = jit->read_cell();
faluco@2029
   681
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   682
	{
ds@1952
   683
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   684
	} else {
ds@1952
   685
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
ds@1952
   686
	}
ds@1952
   687
}
ds@1952
   688
ds@1952
   689
inline void WriteOp_Load_Alt(JitWriter *jit)
ds@1952
   690
{
ds@1952
   691
	//mov edx, [ebp+<val>]
ds@1952
   692
	cell_t val = jit->read_cell();
faluco@2029
   693
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   694
	{
ds@1952
   695
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   696
	} else {
ds@1952
   697
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
ds@1952
   698
	}
ds@1952
   699
}
ds@1952
   700
ds@1952
   701
inline void WriteOp_Load_S_Pri(JitWriter *jit)
ds@1952
   702
{
ds@1952
   703
	//mov eax, [ebx+<val>]
ds@1952
   704
	cell_t val = jit->read_cell();
faluco@2029
   705
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   706
	{
ds@1952
   707
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   708
	} else {
ds@1952
   709
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
ds@1952
   710
	}
ds@1952
   711
}
ds@1952
   712
ds@1952
   713
inline void WriteOp_Load_S_Alt(JitWriter *jit)
ds@1952
   714
{
ds@1952
   715
	//mov edx, [ebx+<val>]
ds@1952
   716
	cell_t val = jit->read_cell();
faluco@2029
   717
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   718
	{
ds@1952
   719
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   720
	} else {
ds@1952
   721
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
ds@1952
   722
	}
ds@1952
   723
}
ds@1952
   724
ds@1952
   725
inline void WriteOp_Lref_Pri(JitWriter *jit)
ds@1952
   726
{
ds@1952
   727
	//mov eax, [ebp+<val>]
ds@1952
   728
	//mov eax, [ebp+eax]
ds@1952
   729
	cell_t val = jit->read_cell();
faluco@2029
   730
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   731
	{
ds@1952
   732
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   733
	} else {
ds@1952
   734
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val);
ds@1952
   735
	}
ds@1952
   736
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
   737
}
ds@1952
   738
ds@1952
   739
inline void WriteOp_Lref_Alt(JitWriter *jit)
ds@1952
   740
{
ds@1952
   741
	//mov edx, [ebp+<val>]
ds@1952
   742
	//mov edx, [ebp+edx]
ds@1952
   743
	cell_t val = jit->read_cell();
faluco@2029
   744
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   745
	{
ds@1952
   746
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   747
	} else {
ds@1952
   748
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val);
ds@1952
   749
	}
ds@1952
   750
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
ds@1952
   751
}
ds@1952
   752
ds@1952
   753
inline void WriteOp_Lref_S_Pri(JitWriter *jit)
ds@1952
   754
{
ds@1952
   755
	//mov eax, [ebx+<val>]
ds@1952
   756
	//mov eax, [ebp+eax]
ds@1952
   757
	cell_t val = jit->read_cell();
faluco@2029
   758
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   759
	{
ds@1952
   760
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   761
	} else {
ds@1952
   762
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val);
ds@1952
   763
	}
ds@1952
   764
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
   765
}
ds@1952
   766
ds@1952
   767
inline void WriteOp_Lref_S_Alt(JitWriter *jit)
ds@1952
   768
{
ds@1952
   769
	//mov edx, [ebx+<val>]
ds@1952
   770
	//mov edx, [ebp+edx]
ds@1952
   771
	cell_t val = jit->read_cell();
faluco@2029
   772
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   773
	{
ds@1952
   774
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   775
	} else {
ds@1952
   776
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val);
ds@1952
   777
	}
ds@1952
   778
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
ds@1952
   779
}
ds@1952
   780
ds@1952
   781
inline void WriteOp_Const_Pri(JitWriter *jit)
ds@1952
   782
{
ds@1952
   783
	//mov eax, <val>
ds@1952
   784
	cell_t val = jit->read_cell();
ds@1952
   785
	IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val);
ds@1952
   786
}
ds@1952
   787
ds@1952
   788
inline void WriteOp_Const_Alt(JitWriter *jit)
ds@1952
   789
{
ds@1952
   790
	//mov edx, <val>
ds@1952
   791
	cell_t val = jit->read_cell();
ds@1952
   792
	IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val);
ds@1952
   793
}
ds@1952
   794
ds@1952
   795
inline void WriteOp_Addr_Pri(JitWriter *jit)
ds@1952
   796
{
ds@1952
   797
	//mov eax, [esi+frm]
ds@1952
   798
	//add eax, <val>
ds@1952
   799
	cell_t val = jit->read_cell();
ds@1952
   800
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
faluco@2029
   801
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   802
	{
ds@1952
   803
		IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG);
ds@1952
   804
	} else {
ds@1952
   805
		IA32_Add_Eax_Imm32(jit, val);
ds@1952
   806
	}
ds@1952
   807
}
ds@1952
   808
ds@1952
   809
inline void WriteOp_Addr_Alt(JitWriter *jit)
ds@1952
   810
{
ds@1952
   811
	//mov edx, [esi+frm]
ds@1952
   812
	//add edx, <val>
ds@1952
   813
	cell_t val = jit->read_cell();
ds@1952
   814
	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG);
faluco@2029
   815
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   816
	{
ds@1952
   817
		IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG);
ds@1952
   818
	} else {
ds@1952
   819
		IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG);
ds@1952
   820
	}
ds@1952
   821
}
ds@1952
   822
ds@1952
   823
inline void WriteOp_Stor_Pri(JitWriter *jit)
ds@1952
   824
{
ds@1952
   825
	//mov [ebp+<val>], eax
ds@1952
   826
	cell_t val = jit->read_cell();
faluco@2029
   827
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   828
	{
ds@1952
   829
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val);
ds@1952
   830
	} else {
ds@1952
   831
		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val);
ds@1952
   832
	}
ds@1952
   833
}
ds@1952
   834
ds@1952
   835
inline void WriteOp_Stor_Alt(JitWriter *jit)
ds@1952
   836
{
ds@1952
   837
	//mov [ebp+<val>], edx
ds@1952
   838
	cell_t val = jit->read_cell();
faluco@2029
   839
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   840
	{
ds@1952
   841
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val);
ds@1952
   842
	} else {
ds@1952
   843
		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val);
ds@1952
   844
	}
ds@1952
   845
}
ds@1952
   846
ds@1952
   847
inline void WriteOp_Stor_S_Pri(JitWriter *jit)
ds@1952
   848
{
ds@1952
   849
	//mov [ebx+<val>], eax
ds@1952
   850
	cell_t val = jit->read_cell();
faluco@2029
   851
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   852
	{
ds@1952
   853
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val);
ds@1952
   854
	} else {
ds@1952
   855
		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val);
ds@1952
   856
	}
ds@1952
   857
}
ds@1952
   858
ds@1952
   859
inline void WriteOp_Stor_S_Alt(JitWriter *jit)
ds@1952
   860
{
ds@1952
   861
	//mov [ebx+<val>], edx
ds@1952
   862
	cell_t val = jit->read_cell();
faluco@2029
   863
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   864
	{
ds@1952
   865
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val);
ds@1952
   866
	} else {
ds@1952
   867
		IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val);
ds@1952
   868
	}
ds@1952
   869
}
ds@1952
   870
ds@1952
   871
inline void WriteOp_Idxaddr(JitWriter *jit)
ds@1952
   872
{
ds@1952
   873
	//lea eax, [edx+4*eax]
ds@1952
   874
	IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
ds@1952
   875
}
ds@1952
   876
ds@1952
   877
inline void WriteOp_Sref_Pri(JitWriter *jit)
ds@1952
   878
{
ds@1952
   879
	//mov ecx, [ebp+<val>]
ds@1952
   880
	//mov [ebp+ecx], eax
ds@1952
   881
	cell_t val = jit->read_cell();
faluco@2029
   882
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   883
	{
ds@1952
   884
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   885
	} else {
ds@1952
   886
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
ds@1952
   887
	}
ds@1952
   888
	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
ds@1952
   889
}
ds@1952
   890
ds@1952
   891
inline void WriteOp_Sref_Alt(JitWriter *jit)
ds@1952
   892
{
ds@1952
   893
	//mov ecx, [ebp+<val>]
ds@1952
   894
	//mov [ebp+ecx], edx
ds@1952
   895
	cell_t val = jit->read_cell();
faluco@2029
   896
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   897
	{
ds@1952
   898
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
ds@1952
   899
	} else {
ds@1952
   900
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
ds@1952
   901
	}
ds@1952
   902
	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
ds@1952
   903
}
ds@1952
   904
ds@1952
   905
inline void WriteOp_Sref_S_Pri(JitWriter *jit)
ds@1952
   906
{
ds@1952
   907
	//mov ecx, [ebx+<val>]
ds@1952
   908
	//mov [ebp+ecx], eax
ds@1952
   909
	cell_t val = jit->read_cell();
faluco@2029
   910
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   911
	{
ds@1952
   912
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   913
	} else {
ds@1952
   914
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
ds@1952
   915
	}
ds@1952
   916
	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI);
ds@1952
   917
}
ds@1952
   918
ds@1952
   919
inline void WriteOp_Sref_S_Alt(JitWriter *jit)
ds@1952
   920
{
ds@1952
   921
	//mov ecx, [ebx+<val>]
ds@1952
   922
	//mov [ebp+ecx], edx
ds@1952
   923
	cell_t val = jit->read_cell();
faluco@2029
   924
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   925
	{
ds@1952
   926
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
ds@1952
   927
	} else {
ds@1952
   928
		IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
ds@1952
   929
	}
ds@1952
   930
	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT);
ds@1952
   931
}
ds@1952
   932
ds@1952
   933
inline void WriteOp_Pop_Pri(JitWriter *jit)
ds@1952
   934
{
ds@1952
   935
	//mov eax, [edi]
ds@1952
   936
	//add edi, 4
ds@1952
   937
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
ds@1952
   938
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   939
}
ds@1952
   940
ds@1952
   941
inline void WriteOp_Pop_Alt(JitWriter *jit)
ds@1952
   942
{
ds@1952
   943
	//mov edx, [edi]
ds@1952
   944
	//add edi, 4
ds@1952
   945
	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
ds@1952
   946
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
   947
}
ds@1952
   948
ds@1952
   949
inline void WriteOp_Swap_Pri(JitWriter *jit)
ds@1952
   950
{
ds@1952
   951
	//add [edi], eax
ds@1952
   952
	//sub eax, [edi]
ds@1952
   953
	//add [edi], eax
ds@1952
   954
	//neg eax
ds@1952
   955
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
ds@1952
   956
	IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
ds@1952
   957
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG);
ds@1952
   958
	IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG);
ds@1952
   959
}
ds@1952
   960
ds@1952
   961
inline void WriteOp_Swap_Alt(JitWriter *jit)
ds@1952
   962
{
ds@1952
   963
	//add [edi], edx
ds@1952
   964
	//sub edx, [edi]
ds@1952
   965
	//add [edi], edx
ds@1952
   966
	//neg edx
ds@1952
   967
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
ds@1952
   968
	IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG);
ds@1952
   969
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
ds@1952
   970
	IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG);
ds@1952
   971
}
ds@1952
   972
ds@1952
   973
inline void WriteOp_PushAddr(JitWriter *jit)
ds@1952
   974
{
ds@1952
   975
	//mov ecx, [esi+frm]	;get address (offset from frame)
ds@1952
   976
	//sub edi, 4
ds@1952
   977
	//add ecx, <val>
ds@1952
   978
	//mov [edi], ecx
ds@1952
   979
	cell_t val = jit->read_cell();
ds@1952
   980
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG);
ds@1952
   981
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
faluco@2029
   982
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
   983
	{
ds@1952
   984
		IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG);
ds@1952
   985
	} else {
ds@1952
   986
		IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG);
ds@1952
   987
	}
ds@1952
   988
	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
   989
}
ds@1952
   990
ds@1952
   991
inline void WriteOp_Movs(JitWriter *jit)
ds@1952
   992
{
ds@1952
   993
	//cld
ds@1952
   994
	//push esi
ds@1952
   995
	//push edi
ds@1952
   996
	//lea esi, [ebp+eax]
ds@1952
   997
	//lea edi, [ebp+edx]
ds@1952
   998
	//if dword:
ds@1952
   999
	// mov ecx, dword
ds@1952
  1000
	// rep movsd
ds@1952
  1001
	//if byte:
ds@1952
  1002
	// mov ecx, byte
ds@1952
  1003
	// rep movsb
ds@1952
  1004
	//pop edi
ds@1952
  1005
	//pop esi
ds@1952
  1006
	cell_t val = jit->read_cell();
ds@1952
  1007
	unsigned int dwords = val >> 2;
ds@1952
  1008
	unsigned int bytes = val & 0x3;
ds@1952
  1009
ds@1952
  1010
	IA32_Cld(jit);
ds@1952
  1011
	IA32_Push_Reg(jit, REG_ESI);
ds@1952
  1012
	IA32_Push_Reg(jit, REG_EDI);
ds@1952
  1013
	IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
  1014
	IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
ds@1952
  1015
	if (dwords)
ds@1952
  1016
	{
ds@1952
  1017
		IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords);
ds@1952
  1018
		IA32_Rep(jit);
ds@1952
  1019
		IA32_Movsd(jit);
ds@1952
  1020
	}
ds@1952
  1021
	if (bytes)
ds@1952
  1022
	{
ds@1952
  1023
		IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes);
ds@1952
  1024
		IA32_Rep(jit);
ds@1952
  1025
		IA32_Movsb(jit);
ds@1952
  1026
	}
ds@1952
  1027
	IA32_Pop_Reg(jit, REG_EDI);
ds@1952
  1028
	IA32_Pop_Reg(jit, REG_ESI);
ds@1952
  1029
}
ds@1952
  1030
ds@1952
  1031
inline void WriteOp_Fill(JitWriter *jit)
ds@1952
  1032
{
ds@1952
  1033
	//push edi
ds@1952
  1034
	//lea edi, [ebp+edx]
ds@1952
  1035
	//mov ecx, <val> >> 2
ds@1952
  1036
	//cld
ds@1952
  1037
	//rep stosd
ds@1952
  1038
	//pop edi
ds@1952
  1039
	unsigned int val = jit->read_cell() >> 2;
ds@1952
  1040
ds@1952
  1041
	IA32_Push_Reg(jit, REG_EDI);
ds@1952
  1042
	IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
ds@1952
  1043
	IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
ds@1952
  1044
	IA32_Cld(jit);
ds@1952
  1045
	IA32_Rep(jit);
ds@1952
  1046
	IA32_Stosd(jit);
ds@1952
  1047
	IA32_Pop_Reg(jit, REG_EDI);
ds@1952
  1048
}
ds@1952
  1049
ds@1952
  1050
inline void WriteOp_GenArray(JitWriter *jit, bool autozero)
ds@1952
  1051
{
ds@1952
  1052
	cell_t val = jit->read_cell();
ds@1952
  1053
	if (val == 1)
ds@1952
  1054
	{
ds@1952
  1055
		/* flat array.  we can generate this without indirection tables. */
ds@1952
  1056
		/* Note that we can overwrite ALT because technically STACK should be destroying ALT */
ds@1952
  1057
		//mov edx, [esi+info.heap]
ds@1952
  1058
		//mov ecx, [edi]
ds@1952
  1059
		//mov [edi], edx			;store base of array into stack
ds@1952
  1060
		//lea edx, [edx+ecx*4]		;get the final new heap pointer
ds@1952
  1061
		//mov [esi+info.heap], edx	;store heap pointer back
ds@1952
  1062
		//add edx, ebp				;relocate
ds@1952
  1063
		//cmp edx, edi				;compare against stack pointer
ds@1952
  1064
		//jae :error				;error out if not enough space
ds@1952
  1065
		IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
ds@1952
  1066
		IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
ds@1952
  1067
		IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG);
ds@1952
  1068
		IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4);
ds@1952
  1069
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP);
ds@1952
  1070
		IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG);
ds@1952
  1071
		IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG);
dvander@2226
  1072
		IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow);
ds@1952
  1073
ds@1952
  1074
		WriteOp_Tracker_Push_Reg(jit, REG_ECX);
ds@1952
  1075
ds@1952
  1076
		if (autozero)
ds@1952
  1077
		{
ds@1952
  1078
			/* Zero out the array - inline a quick fill */
ds@1952
  1079
			//push eax				;save pri
ds@1952
  1080
			//push edi				;save stk
ds@1952
  1081
			//xor eax, eax			;zero source
ds@1952
  1082
			//mov edi, [edi]		;get heap ptr out of the stack
ds@1952
  1083
			//add edi, ebp			;relocate
ds@1952
  1084
			//cld					;clear direction flag
ds@1952
  1085
			//rep stosd				;copy (note: ECX is sane from above)
ds@1952
  1086
			//pop edi				;pop stk
ds@1952
  1087
			//pop eax				;pop pri
ds@1952
  1088
			IA32_Push_Reg(jit, REG_EAX);
ds@1952
  1089
			IA32_Push_Reg(jit, REG_EDI);
ds@1952
  1090
			IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG);
ds@1952
  1091
			IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG);
ds@1952
  1092
			IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
ds@1952
  1093
			IA32_Cld(jit);
ds@1952
  1094
			IA32_Rep(jit);
ds@1952
  1095
			IA32_Stosd(jit);
ds@1952
  1096
			IA32_Pop_Reg(jit, REG_EDI);
ds@1952
  1097
			IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  1098
		}
ds@1952
  1099
	} else {
ds@1952
  1100
		//mov ecx, num_dims
ds@1952
  1101
		//mov edx, 0/1
ds@1952
  1102
		//call [genarray]
ds@1952
  1103
		IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val);
ds@1952
  1104
		if (autozero)
ds@1952
  1105
		{
ds@1952
  1106
			IA32_Mov_Reg_Imm32(jit, REG_EDX, 1);
ds@1952
  1107
		} else {
ds@1952
  1108
			IA32_Mov_Reg_Imm32(jit, REG_EDX, 0);
ds@1952
  1109
		}
ds@1952
  1110
		jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@2226
  1111
		IA32_Write_Jump32_Abs(jit, call, g_Jit.GetGenArrayIntrinsic());
ds@1952
  1112
	}
ds@1952
  1113
}
ds@1952
  1114
ds@1952
  1115
inline void WriteOp_Load_Both(JitWriter *jit)
ds@1952
  1116
{
ds@1952
  1117
	WriteOp_Load_Pri(jit);
ds@1952
  1118
	WriteOp_Load_Alt(jit);
ds@1952
  1119
}
ds@1952
  1120
ds@1952
  1121
inline void WriteOp_Load_S_Both(JitWriter *jit)
ds@1952
  1122
{
ds@1952
  1123
	WriteOp_Load_S_Pri(jit);
ds@1952
  1124
	WriteOp_Load_S_Alt(jit);
ds@1952
  1125
}
ds@1952
  1126
ds@1952
  1127
inline void WriteOp_Const(JitWriter *jit)
ds@1952
  1128
{
ds@1952
  1129
	//mov [ebp+<addr>], <val>
ds@1952
  1130
	cell_t addr = jit->read_cell();
ds@1952
  1131
	cell_t val = jit->read_cell();
faluco@2029
  1132
	if (addr <= SCHAR_MAX && addr >= SCHAR_MIN)
ds@1952
  1133
	{
ds@1952
  1134
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr);
ds@1952
  1135
	} else {
ds@1952
  1136
		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr);
ds@1952
  1137
	}
ds@1952
  1138
}
ds@1952
  1139
ds@1952
  1140
inline void WriteOp_Const_S(JitWriter *jit)
ds@1952
  1141
{
ds@1952
  1142
	//mov [ebx+<offs>], <val>
ds@1952
  1143
	cell_t offs = jit->read_cell();
ds@1952
  1144
	cell_t val = jit->read_cell();
faluco@2029
  1145
	if (offs <= SCHAR_MAX && offs >= SCHAR_MIN)
ds@1952
  1146
	{
ds@1952
  1147
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs);
ds@1952
  1148
	} else {
ds@1952
  1149
		IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs);
ds@1952
  1150
	}
ds@1952
  1151
}
ds@1952
  1152
ds@1952
  1153
inline void WriteOp_Load_I(JitWriter *jit)
ds@1952
  1154
{
ds@1952
  1155
	//mov eax, [ebp+eax]
ds@1952
  1156
	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
ds@1952
  1157
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
  1158
}
ds@1952
  1159
ds@1952
  1160
inline void WriteOp_Lodb_I(JitWriter *jit)
ds@1952
  1161
{
ds@1952
  1162
	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
ds@1952
  1163
ds@1952
  1164
	//mov eax, [ebp+eax]
ds@1952
  1165
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
  1166
ds@1952
  1167
	//and eax, <bitmask>
ds@1952
  1168
	cell_t val = jit->read_cell();
ds@1952
  1169
	switch(val)
ds@1952
  1170
	{
ds@1952
  1171
	case 1:
ds@1952
  1172
		{
ds@1952
  1173
			IA32_And_Eax_Imm32(jit, 0x000000FF);
ds@1952
  1174
			break;
ds@1952
  1175
		}
ds@1952
  1176
	case 2:
ds@1952
  1177
		{
ds@1952
  1178
			IA32_And_Eax_Imm32(jit, 0x0000FFFF);
ds@1952
  1179
			break;
ds@1952
  1180
		}
ds@1952
  1181
	}
ds@1952
  1182
}
ds@1952
  1183
ds@1952
  1184
inline void WriteOp_Stor_I(JitWriter *jit)
ds@1952
  1185
{
ds@1952
  1186
	//mov [ebp+edx], eax
ds@1952
  1187
	Write_Check_VerifyAddr(jit, AMX_REG_ALT);
ds@1952
  1188
	IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
ds@1952
  1189
}
ds@1952
  1190
ds@1952
  1191
inline void WriteOp_Strb_I(JitWriter *jit)
ds@1952
  1192
{
ds@1952
  1193
	Write_Check_VerifyAddr(jit, AMX_REG_ALT);
ds@1952
  1194
	//mov [ebp+edx], eax
ds@1952
  1195
	cell_t val = jit->read_cell();
ds@1952
  1196
	switch (val)
ds@1952
  1197
	{
ds@1952
  1198
	case 1:
ds@1952
  1199
		{
ds@1952
  1200
			IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
ds@1952
  1201
			break;
ds@1952
  1202
		}
ds@1952
  1203
	case 2:
ds@1952
  1204
		{
ds@1952
  1205
			IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
ds@1952
  1206
			break;
ds@1952
  1207
		}
ds@1952
  1208
	case 4:
ds@1952
  1209
		{
ds@1952
  1210
			IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI);
ds@1952
  1211
			break;
ds@1952
  1212
		}
ds@1952
  1213
	}
ds@1952
  1214
}
ds@1952
  1215
ds@1952
  1216
inline void WriteOp_Lidx(JitWriter *jit)
ds@1952
  1217
{
ds@1952
  1218
	//lea eax, [edx+4*eax]
ds@1952
  1219
	//mov eax, [ebp+eax]
ds@1952
  1220
	IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4);
ds@1952
  1221
	Write_Check_VerifyAddr(jit, AMX_REG_PRI);
ds@1952
  1222
	IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
ds@1952
  1223
}
ds@1952
  1224
ds@1952
  1225
inline void WriteOp_Stack(JitWriter *jit)
ds@1952
  1226
{
ds@1952
  1227
	//add edi, <val>
ds@1952
  1228
	cell_t val = jit->read_cell();
faluco@2029
  1229
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
  1230
	{
ds@1952
  1231
		IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG);
ds@1952
  1232
	} else {
ds@1952
  1233
		IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG);
ds@1952
  1234
	}
ds@1952
  1235
ds@1952
  1236
	if (val > 0)
ds@1952
  1237
	{
ds@1952
  1238
		Write_CheckStack_Min(jit);
ds@1952
  1239
	} else if (val < 0) {
ds@1952
  1240
		Write_CheckStack_Low(jit);
ds@1952
  1241
	}
ds@1952
  1242
}
ds@1952
  1243
ds@1952
  1244
inline void WriteOp_StackAdjust(JitWriter *jit)
ds@1952
  1245
{
ds@1952
  1246
	cell_t val = jit->read_cell();
ds@1952
  1247
ds@1952
  1248
	assert(val <= 0);
ds@1952
  1249
ds@1952
  1250
	//lea edi, [ebx-val]
ds@1952
  1251
	
faluco@2029
  1252
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
  1253
	{
ds@1952
  1254
		IA32_Lea_DispRegImm8(jit, AMX_REG_STK, AMX_REG_FRM, val);
ds@1952
  1255
	}
ds@1952
  1256
	else
ds@1952
  1257
	{
ds@1952
  1258
		IA32_Lea_DispRegImm32(jit, AMX_REG_STK, AMX_REG_FRM, val);
ds@1952
  1259
	}
ds@1952
  1260
ds@1952
  1261
	/* We assume the compiler has generated good code -- 
ds@1952
  1262
	 * That is, we do not bother validating this amount!
ds@1952
  1263
	 */
ds@1952
  1264
}
ds@1952
  1265
ds@1952
  1266
inline void WriteOp_Heap(JitWriter *jit)
ds@1952
  1267
{
ds@1952
  1268
	//mov edx, [esi+hea]
ds@1952
  1269
	//add [esi+hea], <val>
ds@1952
  1270
	cell_t val = jit->read_cell();
ds@1952
  1271
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP);
faluco@2029
  1272
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
  1273
	{
ds@1952
  1274
		IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP);
ds@1952
  1275
	} else {
ds@1952
  1276
		IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP);
ds@1952
  1277
	}
ds@1952
  1278
ds@1952
  1279
	/* NOTE: Backwards from op.stack */
ds@1952
  1280
	if (val > 0)
ds@1952
  1281
	{
ds@1952
  1282
		Write_CheckHeap_Low(jit);
ds@1952
  1283
	} else if (val < 0) {
ds@1952
  1284
		Write_CheckHeap_Min(jit);
ds@1952
  1285
	}
ds@1952
  1286
}
ds@1952
  1287
ds@1952
  1288
inline void WriteOp_SDiv(JitWriter *jit)
ds@1952
  1289
{
ds@1952
  1290
	//mov ecx, edx
ds@1952
  1291
	//mov edx, eax
ds@1952
  1292
	//sar edx, 31
ds@1952
  1293
	//idiv ecx
ds@1952
  1294
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
ds@1952
  1295
	IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG);
ds@1952
  1296
	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
ds@1952
  1297
	Write_Check_DivZero(jit, AMX_REG_TMP);
ds@1952
  1298
	IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
ds@1952
  1299
}
ds@1952
  1300
ds@1952
  1301
inline void WriteOp_SDiv_Alt(JitWriter *jit)
ds@1952
  1302
{
ds@1952
  1303
	//mov ecx, eax
ds@1952
  1304
	//mov eax, edx
ds@1952
  1305
	//sar edx, 31
ds@1952
  1306
	//idiv ecx
ds@1952
  1307
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
ds@1952
  1308
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
ds@1952
  1309
	IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG);
ds@1952
  1310
	Write_Check_DivZero(jit, AMX_REG_TMP);
ds@1952
  1311
	IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG);
ds@1952
  1312
}
ds@1952
  1313
ds@1952
  1314
inline void WriteOp_Retn(JitWriter *jit)
ds@1952
  1315
{
ds@1952
  1316
	//mov ebx, [edi+4]		- get old frm
ds@1952
  1317
	//add edi, 8			- pop stack
ds@1952
  1318
	//mov [esi+frm], ebx	- restore frame pointer
ds@1952
  1319
	//add ebx, ebp			- relocate
ds@1952
  1320
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4);
ds@1952
  1321
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  1322
	IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG);
ds@1952
  1323
	IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG);
ds@1952
  1324
ds@1952
  1325
	/* pop params */
ds@1952
  1326
	//mov ecx, [edi]
ds@1952
  1327
	//lea edi, [edi+ecx*4+4] 
ds@1952
  1328
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG);
ds@1952
  1329
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4);
ds@1952
  1330
ds@1952
  1331
	//ret					- return (EIP on real stack!)
ds@1952
  1332
	IA32_Return(jit);
ds@1952
  1333
}
ds@1952
  1334
ds@1952
  1335
void ProfCallGate_Begin(sp_context_t *ctx, const char *name)
ds@1952
  1336
{
dvander@2193
  1337
	((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionBegin((IPluginContext *)ctx->vm[JITVARS_BASECTX], name);
ds@1952
  1338
}
ds@1952
  1339
ds@1952
  1340
void ProfCallGate_End(sp_context_t *ctx)
ds@1952
  1341
{
dvander@2193
  1342
	((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionEnd();
ds@1952
  1343
}
ds@1952
  1344
ds@1952
  1345
const char *find_func_name(sp_plugin_t *plugin, uint32_t offs)
ds@1952
  1346
{
ds@1952
  1347
	uint32_t max, iter;
ds@1952
  1348
	sp_fdbg_symbol_t *sym;
ds@1952
  1349
	sp_fdbg_arraydim_t *arr;
ds@1952
  1350
	uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
ds@1952
  1351
ds@1952
  1352
	max = plugin->debug.syms_num;
ds@1952
  1353
	for (iter = 0; iter < max; iter++)
ds@1952
  1354
	{
ds@1952
  1355
		sym = (sp_fdbg_symbol_t *)cursor;
ds@1952
  1356
ds@1952
  1357
		if (sym->ident == SP_SYM_FUNCTION
ds@1952
  1358
			&& sym->codestart <= offs 
ds@1952
  1359
			&& sym->codeend > offs)
ds@1952
  1360
		{
ds@1952
  1361
			return plugin->debug.stringbase + sym->name;
ds@1952
  1362
		}
ds@1952
  1363
ds@1952
  1364
		if (sym->dimcount > 0)
ds@1952
  1365
		{
ds@1952
  1366
			cursor += sizeof(sp_fdbg_symbol_t);
ds@1952
  1367
			arr = (sp_fdbg_arraydim_t *)cursor;
ds@1952
  1368
			cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
ds@1952
  1369
			continue;
ds@1952
  1370
		}
ds@1952
  1371
ds@1952
  1372
		cursor += sizeof(sp_fdbg_symbol_t);
ds@1952
  1373
	}
ds@1952
  1374
ds@1952
  1375
	return NULL;
ds@1952
  1376
}
ds@1952
  1377
ds@1952
  1378
inline void WriteOp_Call(JitWriter *jit)
ds@1952
  1379
{
ds@1952
  1380
	cell_t offs;
ds@1952
  1381
	jitoffs_t jmp;
ds@1952
  1382
	CompData *data;
dvander@2226
  1383
	uint32_t func_idx;
dvander@2226
  1384
	
ds@1952
  1385
	data = (CompData *)jit->data; 
ds@1952
  1386
	offs = jit->read_cell();
ds@1952
  1387
dvander@2226
  1388
	/* Get the context + rp */
dvander@2226
  1389
	//mov eax, [esi+ctx]
dvander@2226
  1390
	//mov ecx, [eax+rp]
dvander@2226
  1391
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
dvander@2226
  1392
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, rp));
dvander@2226
  1393
dvander@2226
  1394
	/* Check if the return stack is used up. */
dvander@2226
  1395
	//cmp ecx, <max stack>
dvander@2226
  1396
	//jae :stacklow
dvander@2226
  1397
	IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_ECX, SP_MAX_RETURN_STACK);
dvander@2226
  1398
	IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, data->jit_error_stacklow);
dvander@2226
  1399
	
dvander@2226
  1400
	/* Add us to the return stack */
dvander@2226
  1401
	//mov [eax+ecx*4+cips], cip
dvander@2226
  1402
	IA32_Mov_Rm_Imm32_SIB(jit,
dvander@2226
  1403
		REG_EAX,
dvander@2226
  1404
		(uint8_t *)(jit->inptr - 2) - data->plugin->pcode,
dvander@2226
  1405
		offsetof(sp_context_t, rstk_cips),
dvander@2226
  1406
		REG_ECX,
dvander@2226
  1407
		SCALE4);
dvander@2226
  1408
dvander@2226
  1409
	/* Increment the return stack pointer */
dvander@2226
  1410
	//inc [eax+rp]
dvander@2226
  1411
	if ((int)offsetof(sp_context_t, rp) >= SCHAR_MIN && (int)offsetof(sp_context_t, rp) <= SCHAR_MAX)
ds@1952
  1412
	{
dvander@2226
  1413
		IA32_Inc_Rm_Disp8(jit, REG_EAX, offsetof(sp_context_t, rp));
ds@1952
  1414
	}
ds@1952
  1415
	else
ds@1952
  1416
	{
dvander@2226
  1417
		IA32_Inc_Rm_Disp32(jit, REG_EAX, offsetof(sp_context_t, rp));
dvander@2226
  1418
	}
dvander@2226
  1419
dvander@2226
  1420
	/* Store the CIP of the function we're about to call. */
dvander@2226
  1421
	IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_INFO, offs, AMX_INFO_CIP);
dvander@2226
  1422
dvander@2226
  1423
	/* Call the function */
dvander@2226
  1424
	func_idx = FuncLookup(data, offs);
dvander@2226
  1425
dvander@2226
  1426
	/* We need to emit a delayed thunk instead. */
dvander@2226
  1427
	if (func_idx == 0)
dvander@2226
  1428
	{
dvander@2226
  1429
		if (jit->outbase == NULL)
dvander@2226
  1430
		{
dvander@2226
  1431
			data->num_thunks++;
dvander@2226
  1432
dvander@2226
  1433
			/* We still emit the call because we need consistent size counting */
dvander@2226
  1434
			IA32_Call_Imm32(jit, 0);
dvander@2226
  1435
		}
dvander@2226
  1436
		else
dvander@2226
  1437
		{
dvander@2226
  1438
			call_thunk_t *thunk;
dvander@2226
  1439
dvander@2226
  1440
			/* Find the thunk we're associated with */
dvander@2226
  1441
			thunk = &data->thunks[data->num_thunks];
dvander@2226
  1442
			data->num_thunks++;
dvander@2226
  1443
dvander@2226
  1444
			/* Emit the call, save its target position.
dvander@2226
  1445
			 * Save thunk info, then patch the target to the thunk.
dvander@2226
  1446
			 */
dvander@2226
  1447
			thunk->patch_addr = IA32_Call_Imm32(jit, 0);
dvander@2226
  1448
			thunk->pcode_offs = offs;
dvander@2226
  1449
			IA32_Write_Jump32(jit, thunk->patch_addr, thunk->thunk_addr);
dvander@2226
  1450
		}
dvander@2226
  1451
	}
dvander@2226
  1452
	/* The function is already jitted.  We can emit a direct call. */
dvander@2226
  1453
	else
dvander@2226
  1454
	{
dvander@2226
  1455
		JitFunction *fn;
dvander@2226
  1456
dvander@2226
  1457
		fn = data->runtime->GetJittedFunction(func_idx);
ds@1952
  1458
		jmp = IA32_Call_Imm32(jit, 0);
dvander@2226
  1459
		IA32_Write_Jump32_Abs(jit, jmp, fn->GetEntryAddress());
ds@1952
  1460
	}
dvander@2226
  1461
dvander@2226
  1462
	/* Restore the last cip */
dvander@2226
  1463
	//mov [esi+cip], <cip>
dvander@2226
  1464
	IA32_Mov_Rm_Imm32_Disp8(jit, 
dvander@2226
  1465
		AMX_REG_INFO, 
dvander@2226
  1466
		(uint8_t *)(jit->inptr - 2) - data->plugin->pcode, 
dvander@2226
  1467
		AMX_INFO_CIP);
dvander@2226
  1468
dvander@2226
  1469
	/* Mark us as leaving the last frame. */ 
dvander@2226
  1470
	//mov ecx, [esi+ctx] 
dvander@2226
  1471
	//dec [ecx+rp] 
dvander@2226
  1472
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); 
dvander@2226
  1473
	IA32_Dec_Rm_Disp8(jit, REG_ECX, offsetof(sp_context_t, rp));
ds@1952
  1474
}
ds@1952
  1475
ds@1952
  1476
inline void WriteOp_Bounds(JitWriter *jit)
ds@1952
  1477
{
ds@1952
  1478
	cell_t val = jit->read_cell();
ds@1952
  1479
	
ds@1952
  1480
	//cmp eax, <val>
ds@1952
  1481
	//ja :error
faluco@2029
  1482
	if (val <= SCHAR_MAX && val >= SCHAR_MIN)
ds@1952
  1483
	{
ds@1952
  1484
		IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val);
ds@1952
  1485
	} else {
ds@1952
  1486
		IA32_Cmp_Eax_Imm32(jit, val);
ds@1952
  1487
	}
dvander@2226
  1488
	IA32_Jump_Cond_Imm32_Rel(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds);
ds@1952
  1489
}
ds@1952
  1490
ds@1952
  1491
inline void WriteOp_Halt(JitWriter *jit)
ds@1952
  1492
{
ds@1952
  1493
	AlignMe(jit);
ds@1952
  1494
ds@1952
  1495
	//mov ecx, [esi+ret]
ds@1952
  1496
	//mov [ecx], eax
ds@1952
  1497
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL);
ds@1952
  1498
	IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG);
ds@1952
  1499
	
ds@1952
  1500
	/* :TODO: 
ds@1952
  1501
	 * We don't support sleeping or halting with weird values.
ds@1952
  1502
	 * So we're omitting the mov eax <val> that was here.
ds@1952
  1503
	 */
ds@1952
  1504
	jit->read_cell();
ds@1952
  1505
dvander@2226
  1506
	IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
ds@1952
  1507
}
ds@1952
  1508
ds@1952
  1509
inline void WriteOp_Break(JitWriter *jit)
ds@1952
  1510
{
dvander@2226
  1511
	CompData *data;
dvander@2226
  1512
dvander@2226
  1513
	data = (CompData *)jit->data;
dvander@2226
  1514
dvander@2226
  1515
	//mov [esi+cip], <cip>
dvander@2226
  1516
	IA32_Mov_Rm_Imm32_Disp8(jit, 
dvander@2226
  1517
		AMX_REG_INFO, 
dvander@2226
  1518
		(uint8_t *)(jit->inptr - 1) - data->plugin->pcode, 
dvander@2226
  1519
		AMX_INFO_CIP);
ds@1952
  1520
}
ds@1952
  1521
ds@1952
  1522
inline void WriteOp_Jump(JitWriter *jit)
ds@1952
  1523
{
ds@1952
  1524
	//jmp <offs>
ds@1952
  1525
	cell_t amx_offs = jit->read_cell();
dvander@2226
  1526
	IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, amx_offs, false));
ds@1952
  1527
}
ds@1952
  1528
ds@1952
  1529
inline void WriteOp_Jzer(JitWriter *jit)
ds@1952
  1530
{
ds@1952
  1531
	//test eax, eax
ds@1952
  1532
	//jz <target>
ds@1952
  1533
	cell_t target = jit->read_cell();
ds@1952
  1534
	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
dvander@2226
  1535
	IA32_Jump_Cond_Imm32_Rel(jit, CC_Z, RelocLookup(jit, target, false));
ds@1952
  1536
}
ds@1952
  1537
ds@1952
  1538
inline void WriteOp_Jnz(JitWriter *jit)
ds@1952
  1539
{
ds@1952
  1540
	//test eax, eax
ds@1952
  1541
	//jnz <target>
ds@1952
  1542
	cell_t target = jit->read_cell();
ds@1952
  1543
	IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
dvander@2226
  1544
	IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, RelocLookup(jit, target, false));
ds@1952
  1545
}
ds@1952
  1546
ds@1952
  1547
inline void WriteOp_Jeq(JitWriter *jit)
ds@1952
  1548
{
ds@1952
  1549
	//cmp eax, edx
ds@1952
  1550
	//je <target>
ds@1952
  1551
	cell_t target = jit->read_cell();
ds@1952
  1552
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1553
	IA32_Jump_Cond_Imm32_Rel(jit, CC_E, RelocLookup(jit, target, false));
ds@1952
  1554
}
ds@1952
  1555
ds@1952
  1556
inline void WriteOp_Jneq(JitWriter *jit)
ds@1952
  1557
{
ds@1952
  1558
	//cmp eax, edx
ds@1952
  1559
	//jne <target>
ds@1952
  1560
	cell_t target = jit->read_cell();
ds@1952
  1561
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1562
	IA32_Jump_Cond_Imm32_Rel(jit, CC_NE, RelocLookup(jit, target, false));
ds@1952
  1563
}
ds@1952
  1564
ds@1952
  1565
inline void WriteOp_Jsless(JitWriter *jit)
ds@1952
  1566
{
ds@1952
  1567
	//cmp eax, edx
ds@1952
  1568
	//jl <target>
ds@1952
  1569
	cell_t target = jit->read_cell();
ds@1952
  1570
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1571
	IA32_Jump_Cond_Imm32_Rel(jit, CC_L, RelocLookup(jit, target, false));
ds@1952
  1572
}
ds@1952
  1573
ds@1952
  1574
inline void WriteOp_Jsleq(JitWriter *jit)
ds@1952
  1575
{
ds@1952
  1576
	//cmp eax, edx
ds@1952
  1577
	//jle <target>
ds@1952
  1578
	cell_t target = jit->read_cell();
ds@1952
  1579
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1580
	IA32_Jump_Cond_Imm32_Rel(jit, CC_LE, RelocLookup(jit, target, false));
ds@1952
  1581
}
ds@1952
  1582
ds@1952
  1583
inline void WriteOp_JsGrtr(JitWriter *jit)
ds@1952
  1584
{
ds@1952
  1585
	//cmp eax, edx
ds@1952
  1586
	//jg <target>
ds@1952
  1587
	cell_t target = jit->read_cell();
ds@1952
  1588
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1589
	IA32_Jump_Cond_Imm32_Rel(jit, CC_G, RelocLookup(jit, target, false));
ds@1952
  1590
}
ds@1952
  1591
ds@1952
  1592
inline void WriteOp_JsGeq(JitWriter *jit)
ds@1952
  1593
{
ds@1952
  1594
	//cmp eax, edx
ds@1952
  1595
	//jge <target>
ds@1952
  1596
	cell_t target = jit->read_cell();
ds@1952
  1597
	IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
dvander@2226
  1598
	IA32_Jump_Cond_Imm32_Rel(jit, CC_GE, RelocLookup(jit, target, false));
ds@1952
  1599
}
ds@1952
  1600
ds@1952
  1601
inline void WriteOp_Switch(JitWriter *jit)
ds@1952
  1602
{
ds@1952
  1603
	cell_t offs = jit->read_cell();
ds@1952
  1604
	cell_t *tbl = (cell_t *)((char *)jit->inbase + offs + sizeof(cell_t));
ds@1952
  1605
ds@1952
  1606
	struct casetbl
ds@1952
  1607
	{
ds@1952
  1608
		cell_t val;
ds@1952
  1609
		cell_t offs;
ds@1952
  1610
	};
ds@1952
  1611
ds@1952
  1612
	/* Read the number of cases, then advance by one */
ds@1952
  1613
	cell_t num_cases = *tbl++;
ds@1952
  1614
	if (!num_cases)
ds@1952
  1615
	{
ds@1952
  1616
		/* Special treatment for 0 cases */
ds@1952
  1617
		//jmp <default>
dvander@2226
  1618
		IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, *tbl, false));
ds@1952
  1619
	} else {
ds@1952
  1620
		/* Check if the case layout is fully sequential */
ds@1952
  1621
		casetbl *iter = (casetbl *)(tbl + 1);
ds@1952
  1622
		casetbl *cases = iter;
ds@1952
  1623
		cell_t first = iter[0].val;
ds@1952
  1624
		cell_t last = first;
ds@1952
  1625
		bool sequential = true;
ds@1952
  1626
		for (cell_t i=1; i<num_cases; i++)
ds@1952
  1627
		{
ds@1952
  1628
			if (iter[i].val != ++last)
ds@1952
  1629
			{
ds@1952
  1630
				sequential = false;
ds@1952
  1631
				break;
ds@1952
  1632
			}
ds@1952
  1633
		}
ds@1952
  1634
		/* Time to generate. 
ds@1952
  1635
		 * First check whether the bounds are correct: if (a < LOW || a > HIGH)
ds@1952
  1636
		 * This check is valid for both sequential and non-sequential.
ds@1952
  1637
		 */
ds@1952
  1638
		cell_t low_bound = cases[0].val;
ds@1952
  1639
		if (low_bound != 0)
ds@1952
  1640
		{
ds@1952
  1641
			/* negate it so we'll get a lower bound of 0 */
ds@1952
  1642
			//lea ecx, [eax-<LOWER_BOUND>]
ds@1952
  1643
			low_bound = -low_bound;
faluco@2029
  1644
			if (low_bound >= SCHAR_MIN && low_bound <= SCHAR_MAX)
ds@1952
  1645
			{
ds@1952
  1646
				IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
ds@1952
  1647
			} else {
ds@1952
  1648
				IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound);
ds@1952
  1649
			}
ds@1952
  1650
		} else {
ds@1952
  1651
			//mov ecx, eax
ds@1952
  1652
			IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
ds@1952
  1653
		}
ds@1952
  1654
		cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val);
ds@1952
  1655
		//cmp ecx, <UPPER BOUND BOUND>
faluco@2029
  1656
		if (high_bound >= SCHAR_MIN && high_bound <= SCHAR_MAX)
ds@1952
  1657
		{
ds@1952
  1658
			IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound);
ds@1952
  1659
		} else {
ds@1952
  1660
			IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound);
ds@1952
  1661
		}
ds@1952
  1662
		//ja <default case>
dvander@2226
  1663
		IA32_Jump_Cond_Imm32_Rel(jit, CC_A, RelocLookup(jit, *tbl, false));
ds@1952
  1664
ds@1952
  1665
		/**
ds@1952
  1666
		 * Now we've taken the default case out of the way, it's time to do the
ds@1952
  1667
		 * full check, which is different for sequential vs. non-sequential.
ds@1952
  1668
		 */
ds@1952
  1669
		if (sequential)
ds@1952
  1670
		{
ds@1952
  1671
			/* we're now theoretically guaranteed to be jumping to a correct offset.
ds@1952
  1672
			 * ECX still has the correctly bound offset in it, luckily!
ds@1952
  1673
			 * thus, we simply need to relocate ECX and store the cases.
ds@1952
  1674
			 */
ds@1952
  1675
			//lea ecx, [ecx*4]
ds@1952
  1676
			//add ecx, <case table start>
ds@1952
  1677
			IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0);
ds@1952
  1678
			jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG);
ds@1952
  1679
			IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
  1680
			/* The case table starts here.  Go back and write the output pointer. */
ds@1952
  1681
			jitoffs_t cur_pos = jit->get_outputpos();
ds@1952
  1682
			jit->set_outputpos(tbl_offs);
ds@1952
  1683
			jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos));
ds@1952
  1684
			jit->set_outputpos(cur_pos);
ds@1952
  1685
			//now we can write the case table, finally!
ds@1952
  1686
			jit_uint32_t base = (jit_uint32_t)jit->outbase;
ds@1952
  1687
			for (cell_t i=0; i<num_cases; i++)
ds@1952
  1688
			{
ds@1952
  1689
				jit->write_uint32(base + RelocLookup(jit, cases[i].offs, false));
ds@1952
  1690
			}
ds@1952
  1691
		} else {
ds@1952
  1692
			/* The slow version.  Go through each case and generate a check.
ds@1952
  1693
			 * In the future we should replace case tables of more than ~8 cases with a
ds@1952
  1694
			 * hash table lookup.
ds@1952
  1695
			 * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case,
ds@1952
  1696
			 *  but only if we're under N cases or so!
ds@1952
  1697
			 * :THOUGHT: Write out a static btree lookup :)
ds@1952
  1698
			 */
ds@1952
  1699
			cell_t val;
ds@1952
  1700
			for (cell_t i=0; i<num_cases; i++)
ds@1952
  1701
			{
ds@1952
  1702
				val = cases[i].val;
ds@1952
  1703
				//cmp eax, <val> OR cmp al, <val>
faluco@2029
  1704
				if (val >= SCHAR_MIN && val <= SCHAR_MAX)
ds@1952
  1705
				{
ds@1952
  1706
					IA32_Cmp_Al_Imm8(jit, val);
ds@1952
  1707
				} else {
ds@1952
  1708
					IA32_Cmp_Eax_Imm32(jit, cases[i].val);
ds@1952
  1709
				}
dvander@2226
  1710
				IA32_Jump_Cond_Imm32_Rel(jit, CC_E, RelocLookup(jit, cases[i].offs, false));
ds@1952
  1711
			}
ds@1952
  1712
			/* After all this, jump to the default case! */
dvander@2226
  1713
			IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, *tbl, false));
ds@1952
  1714
		}
ds@1952
  1715
	}
ds@1952
  1716
}
ds@1952
  1717
ds@1952
  1718
inline void WriteOp_Casetbl(JitWriter *jit)
ds@1952
  1719
{
ds@1952
  1720
	/* do nothing here, switch does all ze work */
ds@1952
  1721
	cell_t num_cases = jit->read_cell();
ds@1952
  1722
ds@1952
  1723
	/* Two cells per case, one extra case for the default jump */
ds@1952
  1724
	num_cases = (num_cases * 2) + 1;
ds@1952
  1725
	jit->inptr += num_cases;
ds@1952
  1726
}
ds@1952
  1727
ds@1952
  1728
inline void WriteOp_Sysreq_C(JitWriter *jit)
ds@1952
  1729
{
ds@1952
  1730
	/* store the number of parameters on the stack, 
ds@1952
  1731
	 * and store the native index as well.
ds@1952
  1732
	 */
ds@1952
  1733
	cell_t native_index = jit->read_cell();
ds@1952
  1734
dvander@2226
  1735
	if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->num_natives)
ds@1952
  1736
	{
ds@1952
  1737
		((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM;
ds@1952
  1738
		return;
ds@1952
  1739
	}
ds@1952
  1740
ds@1952
  1741
	//mov ecx, <native_index>
ds@1952
  1742
	IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index);
ds@1952
  1743
ds@1952
  1744
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
ds@1952
  1745
	IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c);
ds@1952
  1746
}
ds@1952
  1747
ds@1952
  1748
inline void WriteOp_Sysreq_N(JitWriter *jit)
ds@1952
  1749
{
ds@1952
  1750
	/* The big daddy of opcodes. */
ds@1952
  1751
	cell_t native_index = jit->read_cell();
ds@1952
  1752
	cell_t num_params = jit->read_cell();
ds@1952
  1753
	CompData *data = (CompData *)jit->data;
ds@1952
  1754
dvander@2226
  1755
	if ((uint32_t)native_index >= data->plugin->num_natives)
ds@1952
  1756
	{
ds@1952
  1757
		data->error_set = SP_ERROR_INSTRUCTION_PARAM;
ds@1952
  1758
		return;
ds@1952
  1759
	}
ds@1952
  1760
ds@1952
  1761
	/* store the number of parameters on the stack */
ds@1952
  1762
	//mov [edi-4], num_params
ds@1952
  1763
	//sub edi, 4
ds@1952
  1764
	IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4);
ds@1952
  1765
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  1766
ds@1952
  1767
	/* save registers we will need */
ds@1952
  1768
	//push edx
ds@1952
  1769
	IA32_Push_Reg(jit, AMX_REG_ALT);
ds@1952
  1770
ds@1952
  1771
	/* Align the stack to 16 bytes */
ds@1952
  1772
	//push ebx
ds@1952
  1773
	//mov ebx, esp
ds@1952
  1774
	//and esp, 0xFFFFFF0
ds@1952
  1775
	//sub esp, 4
ds@1952
  1776
	IA32_Push_Reg(jit, REG_EBX);
ds@1952
  1777
	IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
ds@1952
  1778
	IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
ds@1952
  1779
	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  1780
ds@1952
  1781
	/* push some callback stuff */
ds@1952
  1782
	//push edi		; stack
ds@1952
  1783
	//push <native>	; native index
ds@1952
  1784
	IA32_Push_Reg(jit, AMX_REG_STK);
faluco@2029
  1785
	if (native_index <= SCHAR_MAX && native_index >= SCHAR_MIN)
ds@1952
  1786
	{
ds@1952
  1787
		IA32_Push_Imm8(jit, (jit_int8_t)native_index);
ds@1952
  1788
	} else {
ds@1952
  1789
		IA32_Push_Imm32(jit, native_index);
ds@1952
  1790
	}
ds@1952
  1791
ds@1952
  1792
	/* Relocate stack, heap, frm information, then store back */
ds@1952
  1793
	//mov eax, [esi+context]
ds@1952
  1794
	//mov ecx, [esi+hea]
ds@1952
  1795
	//sub edi, ebp
ds@1952
  1796
	//mov [eax+hp], ecx
ds@1952
  1797
	//mov ecx, [esi]
ds@1952
  1798
	//mov [eax+sp], edi
ds@1952
  1799
	//mov [eax+frm], ecx
ds@1952
  1800
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
ds@1952
  1801
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
ds@1952
  1802
	IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
ds@1952
  1803
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
ds@1952
  1804
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
ds@1952
  1805
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
ds@1952
  1806
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
ds@1952
  1807
ds@1952
  1808
	/* finally, push the last parameter and make the call */
ds@1952
  1809
	//push eax		; context
ds@1952
  1810
	//call NativeCallback
ds@1952
  1811
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  1812
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@2226
  1813
	if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES)
ds@1952
  1814
	{
dvander@2226
  1815
		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Profile);
ds@1952
  1816
	}
ds@1952
  1817
	else
ds@1952
  1818
	{
dvander@2226
  1819
		IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
ds@1952
  1820
	}
ds@1952
  1821
	
ds@1952
  1822
	/* check for errors */
ds@1952
  1823
	//mov ecx, [esi+context]
ds@1952
  1824
	//cmp [ecx+err], 0
ds@1952
  1825
	//jnz :error
ds@1952
  1826
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
ds@1952
  1827
	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
dvander@2226
  1828
	IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, data->jit_extern_error);
ds@1952
  1829
ds@1952
  1830
	/* restore what we damaged */
ds@1952
  1831
	//mov esp, ebx
ds@1952
  1832
	//pop ebx
ds@1952
  1833
	//add edi, ebp
ds@1952
  1834
	//pop edx
ds@1952
  1835
	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
ds@1952
  1836
	IA32_Pop_Reg(jit, REG_EBX);
ds@1952
  1837
	IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
ds@1952
  1838
	IA32_Pop_Reg(jit, AMX_REG_ALT);
ds@1952
  1839
ds@1952
  1840
	/* pop the stack.  do not check the margins.
ds@1952
  1841
	 * Note that this is not a true macro - we don't bother to
ds@1952
  1842
	 * set ALT here because nothing will be using it.
ds@1952
  1843
	 */
ds@1952
  1844
	num_params++;
ds@1952
  1845
	num_params *= 4;
ds@1952
  1846
	//add edi, <val*4+4>
faluco@2029
  1847
	if (num_params <= SCHAR_MAX && num_params >= SCHAR_MIN)
ds@1952
  1848
	{
ds@1952
  1849
		IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG);
ds@1952
  1850
	} else {
ds@1952
  1851
		IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG);
ds@1952
  1852
	}
ds@1952
  1853
}
ds@1952
  1854
ds@1952
  1855
inline void WriteOp_Tracker_Push_C(JitWriter *jit)
ds@1952
  1856
{
ds@1952
  1857
	cell_t val = jit->read_cell();
ds@1952
  1858
ds@1952
  1859
	/* Save registers that may be damaged by the call */
ds@1952
  1860
	//push eax
ds@1952
  1861
	//push edx
ds@1952
  1862
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  1863
	IA32_Push_Reg(jit, AMX_REG_ALT);
ds@1952
  1864
ds@1952
  1865
	/* Get the context ptr, push it and call the check */
ds@1952
  1866
	//mov eax, [esi+context]
ds@1952
  1867
	//push eax
ds@1952
  1868
	//call JIT_VerifyOrAllocateTracker
ds@1952
  1869
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
ds@1952
  1870
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  1871
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
ds@1952
  1872
	IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
ds@1952
  1873
ds@1952
  1874
	/* Check for errors */
ds@1952
  1875
	//cmp eax, 0
ds@1952
  1876
	//jnz :error
ds@1952
  1877
	IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
dvander@2226
  1878
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
ds@1952
  1879
ds@1952
  1880
	/* Restore */
ds@1952
  1881
	//pop eax
ds@1952
  1882
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  1883
ds@1952
  1884
	/* Push the value into the stack and increment pCur */
ds@1952
  1885
	//mov edx, [eax+vm[]]
ds@1952
  1886
	//mov ecx, [edx+pcur]
ds@1952
  1887
	//add [edx+pcur], 4
ds@1952
  1888
	//mov [ecx], <val>*4	; we want the count in bytes not in cells
ds@1952
  1889
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
ds@1952
  1890
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
ds@1952
  1891
	IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
ds@1952
  1892
	IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG);
ds@1952
  1893
ds@1952
  1894
	/* Restore PRI & ALT */
ds@1952
  1895
	//pop edx
ds@1952
  1896
	//pop eax
ds@1952
  1897
	IA32_Pop_Reg(jit, AMX_REG_ALT);
ds@1952
  1898
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  1899
}
ds@1952
  1900
ds@1952
  1901
inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit)
ds@1952
  1902
{
ds@1952
  1903
	/* Save registers that may be damaged by the call */
ds@1952
  1904
	//push eax
ds@1952
  1905
	//push edx
ds@1952
  1906
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  1907
	IA32_Push_Reg(jit, AMX_REG_ALT);
ds@1952
  1908
ds@1952
  1909
	/* Get the context ptr, push it and call the check */
ds@1952
  1910
	//mov eax, [esi+context]
ds@1952
  1911
	//push eax
ds@1952
  1912
	//call JIT_VerifyLowBoundTracker
ds@1952
  1913
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
ds@1952
  1914
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  1915
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
ds@1952
  1916
	IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyLowBoundTracker);
ds@1952
  1917
ds@1952
  1918
	/* Check for errors */
ds@1952
  1919
	//cmp eax, 0
ds@1952
  1920
	//jnz :error
ds@1952
  1921
	IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
dvander@2226
  1922
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
ds@1952
  1923
ds@1952
  1924
	/* Restore */
ds@1952
  1925
	//pop eax
ds@1952
  1926
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  1927
ds@1952
  1928
	/* Pop the value from the stack and decrease the heap by it*/
ds@1952
  1929
	//mov edx, [eax+vm[]]
ds@1952
  1930
	//sub [edx+pcur], 4
ds@1952
  1931
	//mov ecx, [edx+pcur]
ds@1952
  1932
	//mov ecx, [ecx]
ds@1952
  1933
	//sub [esi+hea], ecx
ds@1952
  1934
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
ds@1952
  1935
	IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
ds@1952
  1936
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur));
ds@1952
  1937
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG);
ds@1952
  1938
	IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP);
ds@1952
  1939
ds@1952
  1940
	Write_CheckHeap_Min(jit);
ds@1952
  1941
ds@1952
  1942
	/* Restore PRI & ALT */
ds@1952
  1943
	//pop edx
ds@1952
  1944
	//pop eax
ds@1952
  1945
	IA32_Pop_Reg(jit, AMX_REG_ALT);
ds@1952
  1946
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  1947
}
ds@1952
  1948
ds@1952
  1949
inline void WriteOp_Stradjust_Pri(JitWriter *jit)
ds@1952
  1950
{
ds@1952
  1951
	//add eax, 4
ds@1952
  1952
	//sar eax, 2
ds@1952
  1953
	IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 4, MOD_REG);
ds@1952
  1954
	IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 2, MOD_REG);
ds@1952
  1955
}
ds@1952
  1956
ds@1952
  1957
inline void WriteOp_FloatAbs(JitWriter *jit)
ds@1952
  1958
{
ds@1952
  1959
	//mov eax, [edi]
ds@1952
  1960
	//and eax, 0x7FFFFFFF
ds@1952
  1961
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG);
ds@1952
  1962
	IA32_And_Eax_Imm32(jit, 0x7FFFFFFF);
ds@1952
  1963
ds@1952
  1964
	/* Rectify the stack */
ds@1952
  1965
	//add edi, 4
ds@1952
  1966
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  1967
}
ds@1952
  1968
ds@1952
  1969
inline void WriteOp_Float(JitWriter *jit)
ds@1952
  1970
{
ds@1952
  1971
	//fild [edi]
ds@1952
  1972
	//push eax
ds@1952
  1973
	//fstp [esp]
ds@1952
  1974
	//pop eax
ds@1952
  1975
	IA32_Fild_Mem32(jit, AMX_REG_STK);
ds@1952
  1976
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  1977
	IA32_Fstp_Mem32_ESP(jit);
ds@1952
  1978
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  1979
ds@1952
  1980
	/* Rectify the stack */
ds@1952
  1981
	//add edi, 4
ds@1952
  1982
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  1983
}
ds@1952
  1984
ds@1952
  1985
inline void WriteOp_FloatAdd(JitWriter *jit)
ds@1952
  1986
{
ds@1952
  1987
	//push eax
ds@1952
  1988
	//fld [edi]
ds@1952
  1989
	//fadd [edi+4]
ds@1952
  1990
	//fstp [esp]
ds@1952
  1991
	//pop eax
ds@1952
  1992
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  1993
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  1994
	IA32_Fadd_Mem32_Disp8(jit, AMX_REG_STK, 4);
ds@1952
  1995
	IA32_Fstp_Mem32_ESP(jit);
ds@1952
  1996
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  1997
ds@1952
  1998
	/* Rectify the stack */
ds@1952
  1999
	//add edi, 8
ds@1952
  2000
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  2001
}
ds@1952
  2002
ds@1952
  2003
inline void WriteOp_FloatSub(JitWriter *jit)
ds@1952
  2004
{
ds@1952
  2005
	//push eax
ds@1952
  2006
	//fld [edi]
ds@1952
  2007
	//fsub [edi+4]
ds@1952
  2008
	//fstp [esp]
ds@1952
  2009
	//pop eax
ds@1952
  2010
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  2011
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2012
	IA32_Fsub_Mem32_Disp8(jit, AMX_REG_STK, 4);
ds@1952
  2013
	IA32_Fstp_Mem32_ESP(jit);
ds@1952
  2014
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  2015
ds@1952
  2016
	/* Rectify the stack */
ds@1952
  2017
	//add edi, 8
ds@1952
  2018
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  2019
}
ds@1952
  2020
ds@1952
  2021
inline void WriteOp_FloatMul(JitWriter *jit)
ds@1952
  2022
{
ds@1952
  2023
	//push eax
ds@1952
  2024
	//fld [edi]
ds@1952
  2025
	//fmul [edi+4]
ds@1952
  2026
	//fstp [esp]
ds@1952
  2027
	//pop eax
ds@1952
  2028
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  2029
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2030
	IA32_Fmul_Mem32_Disp8(jit, AMX_REG_STK, 4);
ds@1952
  2031
	IA32_Fstp_Mem32_ESP(jit);
ds@1952
  2032
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  2033
ds@1952
  2034
	/* Rectify the stack */
ds@1952
  2035
	//add edi, 8
ds@1952
  2036
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  2037
}
ds@1952
  2038
ds@1952
  2039
inline void WriteOp_FloatDiv(JitWriter *jit)
ds@1952
  2040
{
ds@1952
  2041
	//push eax
ds@1952
  2042
	//fld [edi]
ds@1952
  2043
	//fdiv [edi+4]
ds@1952
  2044
	//fstp [esp]
ds@1952
  2045
	//pop eax
ds@1952
  2046
	IA32_Push_Reg(jit, AMX_REG_PRI);
ds@1952
  2047
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2048
	IA32_Fdiv_Mem32_Disp8(jit, AMX_REG_STK, 4);
ds@1952
  2049
	IA32_Fstp_Mem32_ESP(jit);
ds@1952
  2050
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  2051
ds@1952
  2052
	/* Rectify the stack */
ds@1952
  2053
	//add edi, 8
ds@1952
  2054
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  2055
}
ds@1952
  2056
ds@1952
  2057
inline void WriteOp_RountToNearest(JitWriter *jit)
ds@1952
  2058
{
ds@1952
  2059
	//push eax
ds@1952
  2060
	//fld [edi]
ds@1952
  2061
ds@1952
  2062
	//fstcw [esp]
ds@1952
  2063
	//mov eax, [esp]
ds@1952
  2064
	//push eax
ds@1952
  2065
ds@1952
  2066
	//mov [esp+4], 0x3FF
ds@1952
  2067
	//fadd st(0), st(0)
ds@1952
  2068
	//fldcw [esp+4]
ds@1952
  2069
ds@1952
  2070
	//push eax	
ds@1952
  2071
	//push 0x3F000000 ; 0.5f
ds@1952
  2072
	//fadd [esp]
ds@1952
  2073
	//fistp [esp+4]
ds@1952
  2074
	//pop eax
ds@1952
  2075
	//pop eax
ds@1952
  2076
ds@1952
  2077
	//pop ecx
ds@1952
  2078
	//sar eax, 1
ds@1952
  2079
	//mov [esp], ecx
ds@1952
  2080
	//fldcw [esp]
ds@1952
  2081
	//add esp, 4
ds@1952
  2082
ds@1952
  2083
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2084
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2085
ds@1952
  2086
	IA32_Fstcw_Mem16_ESP(jit);
ds@1952
  2087
	IA32_Mov_Reg_RmESP(jit, REG_EAX);
ds@1952
  2088
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2089
ds@1952
  2090
	IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x3FF);
ds@1952
  2091
	IA32_Fadd_FPUreg_ST0(jit, 0);
ds@1952
  2092
	IA32_Fldcw_Mem16_Disp8_ESP(jit, 4);
ds@1952
  2093
ds@1952
  2094
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2095
	IA32_Push_Imm32(jit, 0x3F000000);
ds@1952
  2096
	IA32_Fadd_Mem32_ESP(jit);
ds@1952
  2097
	IA32_Fistp_Mem32_Disp8_Esp(jit, 4);
ds@1952
  2098
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  2099
	IA32_Pop_Reg(jit, AMX_REG_PRI);
ds@1952
  2100
ds@1952
  2101
	IA32_Pop_Reg(jit, REG_ECX);
ds@1952
  2102
	IA32_Sar_Rm_1(jit, REG_EAX, MOD_REG);
ds@1952
  2103
	IA32_Mov_RmESP_Reg(jit, REG_ECX);
ds@1952
  2104
	IA32_Fldcw_Mem16_ESP(jit);
ds@1952
  2105
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  2106
ds@1952
  2107
	/* Rectify the stack */
ds@1952
  2108
	//add edi, 4
ds@1952
  2109
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  2110
}
ds@1952
  2111
ds@1952
  2112
inline void WriteOp_RoundToFloor(JitWriter *jit)
ds@1952
  2113
{
ds@1952
  2114
	//push eax
ds@1952
  2115
	//fld [edi]
ds@1952
  2116
ds@1952
  2117
	//fstcw [esp]
ds@1952
  2118
	//mov eax, [esp]
ds@1952
  2119
	//push eax
ds@1952
  2120
ds@1952
  2121
	//mov [esp+4], 0x7FF
ds@1952
  2122
	//fldcw [esp+4]
ds@1952
  2123
ds@1952
  2124
	//push eax	
ds@1952
  2125
	//fistp [esp]
ds@1952
  2126
	//pop eax
ds@1952
  2127
ds@1952
  2128
	//pop ecx
ds@1952
  2129
	//mov [esp], ecx
ds@1952
  2130
	//fldcw [esp]
ds@1952
  2131
	//add esp, 4
ds@1952
  2132
ds@1952
  2133
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2134
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2135
ds@1952
  2136
	IA32_Fstcw_Mem16_ESP(jit);
ds@1952
  2137
	IA32_Mov_Reg_RmESP(jit, REG_EAX);
ds@1952
  2138
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2139
ds@1952
  2140
	IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x7FF);
ds@1952
  2141
	IA32_Fldcw_Mem16_Disp8_ESP(jit, 4);
ds@1952
  2142
ds@1952
  2143
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2144
	IA32_Fistp_Mem32_ESP(jit);
ds@1952
  2145
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  2146
ds@1952
  2147
	IA32_Pop_Reg(jit, REG_ECX);
ds@1952
  2148
	IA32_Mov_RmESP_Reg(jit, REG_ECX);
ds@1952
  2149
	IA32_Fldcw_Mem16_ESP(jit);
ds@1952
  2150
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  2151
ds@1952
  2152
	/* Rectify the stack */
ds@1952
  2153
	//add edi, 4
ds@1952
  2154
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  2155
}
ds@1952
  2156
ds@1952
  2157
inline void WriteOp_RoundToCeil(JitWriter *jit)
ds@1952
  2158
{
ds@1952
  2159
	//push eax
ds@1952
  2160
	//fld [edi]
ds@1952
  2161
ds@1952
  2162
	//fstcw [esp]
ds@1952
  2163
	//mov eax, [esp]
ds@1952
  2164
	//push eax
ds@1952
  2165
ds@1952
  2166
	//mov [esp+4], 0xBFF
ds@1952
  2167
	//fldcw [esp+4]
ds@1952
  2168
ds@1952
  2169
	//push eax	
ds@1952
  2170
	//fistp [esp]
ds@1952
  2171
	//pop eax
ds@1952
  2172
ds@1952
  2173
	//pop ecx
ds@1952
  2174
	//mov [esp], ecx
ds@1952
  2175
	//fldcw [esp]
ds@1952
  2176
	//add esp, 4
ds@1952
  2177
ds@1952
  2178
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2179
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2180
ds@1952
  2181
	IA32_Fstcw_Mem16_ESP(jit);
ds@1952
  2182
	IA32_Mov_Reg_RmESP(jit, REG_EAX);
ds@1952
  2183
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2184
ds@1952
  2185
	IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xBFF);
ds@1952
  2186
	IA32_Fldcw_Mem16_Disp8_ESP(jit, 4);
ds@1952
  2187
ds@1952
  2188
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2189
	IA32_Fistp_Mem32_ESP(jit);
ds@1952
  2190
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  2191
ds@1952
  2192
	IA32_Pop_Reg(jit, REG_ECX);
ds@1952
  2193
	IA32_Mov_RmESP_Reg(jit, REG_ECX);
ds@1952
  2194
	IA32_Fldcw_Mem16_ESP(jit);
ds@1952
  2195
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  2196
ds@1952
  2197
	/* Rectify the stack */
ds@1952
  2198
	//add edi, 4
ds@1952
  2199
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  2200
}
ds@1952
  2201
ds@1952
  2202
inline void WriteOp_RoundToZero(JitWriter *jit)
ds@1952
  2203
{
ds@1952
  2204
	//push eax
ds@1952
  2205
	//fld [edi]
ds@1952
  2206
ds@1952
  2207
	//fstcw [esp]
ds@1952
  2208
	//mov eax, [esp]
ds@1952
  2209
	//push eax
ds@1952
  2210
ds@1952
  2211
	//mov [esp+4], 0xFFF
ds@1952
  2212
	//fldcw [esp+4]
ds@1952
  2213
ds@1952
  2214
	//push eax	
ds@1952
  2215
	//fistp [esp]
ds@1952
  2216
	//pop eax
ds@1952
  2217
ds@1952
  2218
	//pop ecx
ds@1952
  2219
	//mov [esp], ecx
ds@1952
  2220
	//fldcw [esp]
ds@1952
  2221
	//add esp, 4
ds@1952
  2222
ds@1952
  2223
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2224
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2225
ds@1952
  2226
	IA32_Fstcw_Mem16_ESP(jit);
ds@1952
  2227
	IA32_Mov_Reg_RmESP(jit, REG_EAX);
ds@1952
  2228
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2229
ds@1952
  2230
	IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xFFF);
ds@1952
  2231
	IA32_Fldcw_Mem16_Disp8_ESP(jit, 4);
ds@1952
  2232
ds@1952
  2233
	IA32_Push_Reg(jit, REG_EAX);
ds@1952
  2234
	IA32_Fistp_Mem32_ESP(jit);
ds@1952
  2235
	IA32_Pop_Reg(jit, REG_EAX);
ds@1952
  2236
ds@1952
  2237
	IA32_Pop_Reg(jit, REG_ECX);
ds@1952
  2238
	IA32_Mov_RmESP_Reg(jit, REG_ECX);
ds@1952
  2239
	IA32_Fldcw_Mem16_ESP(jit);
ds@1952
  2240
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  2241
ds@1952
  2242
	/* Rectify the stack */
ds@1952
  2243
	//add edi, 4
ds@1952
  2244
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
ds@1952
  2245
}
ds@1952
  2246
ds@1952
  2247
inline void WriteOp_FloatCompare(JitWriter *jit)
ds@1952
  2248
{
ds@1952
  2249
	//fld [edi]
ds@1952
  2250
	//fld [edi+4]
ds@1952
  2251
	//fucomip st(0), st(1)
ds@1952
  2252
	//mov ecx, <round_table>
ds@1952
  2253
	//cmovz eax, [ecx+4]
ds@1952
  2254
	//cmovb eax, [ecx+8]
ds@1952
  2255
	//cmova eax, [ecx]
ds@1952
  2256
	//fstp st(0)
ds@1952
  2257
ds@1952
  2258
	IA32_Fld_Mem32(jit, AMX_REG_STK);
ds@1952
  2259
	IA32_Fld_Mem32_Disp8(jit, AMX_REG_STK, 4);
ds@1952
  2260
	IA32_Fucomip_ST0_FPUreg(jit, 1);
dvander@2226
  2261
	IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, (jit_int32_t)g_Jit.GetRoundingTable());
ds@1952
  2262
	IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_Z, 4);
ds@1952
  2263
	IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_B, 8);
ds@1952
  2264
	IA32_CmovCC_Rm(jit, AMX_REG_TMP, CC_A);
ds@1952
  2265
	IA32_Fstp_FPUreg(jit, 0);
ds@1952
  2266
ds@1952
  2267
	/* Rectify the stack */
ds@1952
  2268
	//add edi, 8
ds@1952
  2269
	IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG);
ds@1952
  2270
}
ds@1952
  2271
dvander@2226
  2272
inline void WriteOp_EndProc(JitWriter *jit)
dvander@2226
  2273
{
dvander@2226
  2274
}
dvander@2226
  2275
dvander@2226
  2276
void Write_CallThunk(JitWriter *jit, jitoffs_t jmploc, cell_t pcode_offs)
dvander@2226
  2277
{
dvander@2226
  2278
	CompData *data;
dvander@2226
  2279
	jitoffs_t call;
dvander@2226
  2280
dvander@2226
  2281
	data = (CompData *)jit->data;
dvander@2226
  2282
dvander@2226
  2283
	//push <jmploc_addr>
dvander@2226
  2284
	//push <pcode_offs>
dvander@2226
  2285
	//push <runtime>
dvander@2226
  2286
	//call CompileFromThunk
dvander@2226
  2287
	//add esp, 4*3
dvander@2226
  2288
	//test eax, eax
dvander@2226
  2289
	//jz :error
dvander@2226
  2290
	//call eax
dvander@2226
  2291
	//ret
dvander@2226
  2292
	IA32_Push_Imm32(jit, (jit_int32_t)(jit->outbase + jmploc));
dvander@2226
  2293
	IA32_Push_Imm32(jit, pcode_offs);
dvander@2226
  2294
	IA32_Push_Imm32(jit, (jit_int32_t)(data->runtime));
dvander@2226
  2295
	call = IA32_Call_Imm32(jit, 0);
dvander@2226
  2296
	IA32_Write_Jump32_Abs(jit, call, (void *)CompileThunk);
dvander@2226
  2297
	IA32_Add_Rm_Imm32(jit, REG_ESP, 4*3, MOD_REG);
dvander@2226
  2298
	IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
dvander@2226
  2299
	call = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
dvander@2226
  2300
	IA32_Call_Reg(jit, REG_EAX);
dvander@2226
  2301
	IA32_Return(jit);
dvander@2226
  2302
dvander@2226
  2303
	/* We decrement the frame and store the target cip. */
dvander@2226
  2304
	//:error
dvander@2226
  2305
	//mov [esi+cip], pcode_offs
dvander@2226
  2306
	//goto error
dvander@2226
  2307
	IA32_Send_Jump8_Here(jit, call);
dvander@2226
  2308
	Write_SetError(jit, SP_ERROR_INVALID_INSTRUCTION);
dvander@2226
  2309
}
dvander@2226
  2310
ds@1952
  2311
/*************************************************
ds@1952
  2312
 *************************************************
ds@1952
  2313
 * JIT PROPER ************************************
ds@1952
  2314
 * The rest from now on is the JIT engine        *
ds@1952
  2315
 *************************************************
ds@1952
  2316
 *************************************************/
ds@1952
  2317
dvander@2226
  2318
void *CompileThunk(BaseRuntime *runtime, cell_t pcode_offs, void *jmploc_addr)
dvander@2226
  2319
{
dvander@2226
  2320
	int err;
dvander@2226
  2321
	JitFunction *fn;
dvander@2226
  2322
	uint32_t func_idx;
dvander@2226
  2323
	void *target_addr;
dvander@2226
  2324
	
dvander@2226
  2325
	if ((func_idx = FuncLookup((CompData *)runtime->m_pCo, pcode_offs)) == 0)
dvander@2226
  2326
	{
dvander@2226
  2327
		fn = g_Jit.CompileFunction(runtime, pcode_offs, &err);
dvander@2226
  2328
	}
dvander@2226
  2329
	else
dvander@2226
  2330
	{
dvander@2226
  2331
		fn = runtime->GetJittedFunction(func_idx);
dvander@2226
  2332
dvander@2226
  2333
#if defined _DEBUG
dvander@2226
  2334
		g_engine1.GetDebugHook()->OnDebugSpew("Patching thunk to %s::%s", runtime->m_pPlugin->name, find_func_name(runtime->m_pPlugin, pcode_offs));
dvander@2226
  2335
#endif
dvander@2226
  2336
dvander@2226
  2337
	}
dvander@2226
  2338
dvander@2226
  2339
	if (fn == NULL)
dvander@2226
  2340
	{
dvander@2226
  2341
		return NULL;
dvander@2226
  2342
	}
dvander@2226
  2343
dvander@2226
  2344
	target_addr = fn->GetEntryAddress();
dvander@2226
  2345
dvander@2226
  2346
	/* Right now, we always keep the code RWE */
dvander@2226
  2347
	*(intptr_t *)((char *)jmploc_addr) = 
dvander@2226
  2348
		intptr_t(target_addr) - (intptr_t(jmploc_addr) + 4);
dvander@2226
  2349
dvander@2226
  2350
	return target_addr;
dvander@2226
  2351
}
dvander@2226
  2352
ds@1952
  2353
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
ds@1952
  2354
{
ds@1952
  2355
	sp_native_t *native;
ds@1952
  2356
	cell_t save_sp = ctx->sp;
ds@1952
  2357
	cell_t save_hp = ctx->hp;
dvander@2193
  2358
	sp_plugin_t *pl = GETPLUGIN(ctx);
dvander@2193
  2359
ds@1952
  2360
	ctx->n_idx = native_idx;
ds@1952
  2361
dvander@2193
  2362
	if (ctx->hp < (cell_t)pl->data_size)
ds@1952
  2363
	{
ds@1952
  2364
		ctx->n_err = SP_ERROR_HEAPMIN;
ds@1952
  2365
		return 0;
ds@1952
  2366
	}
ds@1952
  2367
ds@1952
  2368
	if (ctx->hp + STACK_MARGIN > ctx->sp)
ds@1952
  2369
	{
ds@1952
  2370
		ctx->n_err = SP_ERROR_STACKLOW;
ds@1952
  2371
		return 0;
ds@1952
  2372
	}
ds@1952
  2373
dvander@2193
  2374
	if ((uint32_t)ctx->sp >= pl->mem_size)
ds@1952
  2375
	{
ds@1952
  2376
		ctx->n_err = SP_ERROR_STACKMIN;
ds@1952
  2377
		return 0;
ds@1952
  2378
	}
ds@1952
  2379
dvander@2226
  2380
	native = &pl->natives[native_idx];
dvander@2226
  2381
dvander@2226
  2382
	if (native->status == SP_NATIVE_UNBOUND)
dvander@2226
  2383
	{
dvander@2226
  2384
		ctx->n_err = SP_ERROR_INVALID_NATIVE;
dvander@2226
  2385
		return 0;
dvander@2226
  2386
	}
dvander@2226
  2387
dvander@2226
  2388
	cell_t result = native->pfn(GET_CONTEXT(ctx), params);
ds@1952
  2389
ds@1952
  2390
	if (ctx->n_err != SP_ERROR_NONE)
ds@1952
  2391
	{
ds@1952
  2392
		return result;
ds@1952
  2393
	}
ds@1952
  2394
ds@1952
  2395
	if (save_sp != ctx->sp)
ds@1952
  2396
	{
ds@1952
  2397
		ctx->n_err = SP_ERROR_STACKLEAK;
ds@1952
  2398
		return result;
ds@1952
  2399
	}
ds@1952
  2400
	else if (save_hp != ctx->hp)
ds@1952
  2401
	{
ds@1952
  2402
		ctx->n_err = SP_ERROR_HEAPLEAK;
ds@1952
  2403
		return result;
ds@1952
  2404
	}
ds@1952
  2405
ds@1952
  2406
	return result;
ds@1952
  2407
}
ds@1952
  2408
dvander@2226
  2409
cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
ds@1952
  2410
{
dvander@2226
  2411
	/* :TODO: */
dvander@2226
  2412
	return NativeCallback(ctx, native_idx, params);
ds@1952
  2413
}
ds@1952
  2414
dvander@2226
  2415
uint32_t FuncLookup(CompData *data, cell_t pcode_offs)
ds@1952
  2416
{
dvander@2226
  2417
	/* Offset must always be 1)positive and 2)less than or equal to the codesize */
dvander@2226
  2418
	assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->plugin->pcode_size);
dvander@2226
  2419
dvander@2226
  2420
	/* Do the lookup in the native dictionary. */
dvander@2226
  2421
	return *(jitoffs_t *)(data->rebase + pcode_offs);
ds@1952
  2422
}
ds@1952
  2423
ds@1952
  2424
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
ds@1952
  2425
{
ds@1952
  2426
	if (jit->outptr)
ds@1952
  2427
	{
ds@1952
  2428
		CompData *data = (CompData *)jit->data;
ds@1952
  2429
		if (relative)
ds@1952
  2430
		{
ds@1952
  2431
			/* The actual offset is EIP relative. We need to relocate it.
ds@1952
  2432
			 * Note that this assumes that we're pointing to the next op.
ds@1952
  2433
			 */
ds@1952
  2434
			pcode_offs += jit->get_inputpos();
ds@1952
  2435
		}
ds@1952
  2436
		/* Offset must always be 1)positive and 2)less than or equal to the codesize */
dvander@2226
  2437
		assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->plugin->pcode_size);
ds@1952
  2438
		/* Do the lookup in the native dictionary. */
ds@1952
  2439
		return *(jitoffs_t *)(data->rebase + pcode_offs);
ds@1952
  2440
	}
ds@1952
  2441
	else
ds@1952
  2442
	{
ds@1952
  2443
		return 0;
ds@1952
  2444
	}
ds@1952
  2445
}
ds@1952
  2446
ds@1952
  2447
void WriteErrorRoutines(CompData *data, JitWriter *jit)
ds@1952
  2448
{
ds@1952
  2449
	AlignMe(jit);
ds@1952
  2450
ds@1952
  2451
	data->jit_error_divzero = jit->get_outputpos();
ds@1952
  2452
	Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO);
ds@1952
  2453
ds@1952
  2454
	data->jit_error_stacklow = jit->get_outputpos();
ds@1952
  2455
	Write_SetError(jit, SP_ERROR_STACKLOW);
ds@1952
  2456
ds@1952
  2457
	data->jit_error_stackmin = jit->get_outputpos();
ds@1952
  2458
	Write_SetError(jit, SP_ERROR_STACKMIN);
ds@1952
  2459
ds@1952
  2460
	data->jit_error_bounds = jit->get_outputpos();
ds@1952
  2461
	Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS);
ds@1952
  2462
ds@1952
  2463
	data->jit_error_memaccess = jit->get_outputpos();
ds@1952
  2464
	Write_SetError(jit, SP_ERROR_MEMACCESS);
ds@1952
  2465
ds@1952
  2466
	data->jit_error_heaplow = jit->get_outputpos();
ds@1952
  2467
	Write_SetError(jit, SP_ERROR_HEAPLOW);
ds@1952
  2468
ds@1952
  2469
	data->jit_error_heapmin = jit->get_outputpos();
ds@1952
  2470
	Write_SetError(jit, SP_ERROR_HEAPMIN);
ds@1952
  2471
ds@1952
  2472
	data->jit_extern_error = jit->get_outputpos();
ds@1952
  2473
	Write_GetError(jit);
ds@1952
  2474
}
ds@1952
  2475
dvander@2226
  2476
ICompilation *JITX86::ApplyOptions(ICompilation *_IN, ICompilation *_OUT)
ds@1952
  2477
{
dvander@2226
  2478
	if (_IN == NULL)
dvander@2193
  2479
	{
dvander@2226
  2480
		return _OUT;
dvander@2193
  2481
	}
dvander@2193
  2482
dvander@2226
  2483
	CompData *_in = (CompData * )_IN;
dvander@2226
  2484
	CompData *_out = (CompData * )_OUT;
dvander@2226
  2485
dvander@2226
  2486
	_in->inline_level = _out->inline_level;
dvander@2226
  2487
	_in->profile = _out->profile;
dvander@2226
  2488
dvander@2226
  2489
	_out->Abort();
dvander@2226
  2490
dvander@2226
  2491
	return _in;
dvander@2226
  2492
}
dvander@2226
  2493
dvander@2226
  2494
JITX86::JITX86()
dvander@2226
  2495
{
dvander@2226
  2496
	m_pJitEntry = NULL;
dvander@2226
  2497
	m_pJitReturn = NULL;
dvander@2226
  2498
	m_RoundTable[0] = -1;
dvander@2226
  2499
	m_RoundTable[1] = 0;
dvander@2226
  2500
	m_RoundTable[2] = 1;
dvander@2226
  2501
	m_pJitGenArray = NULL;
dvander@2226
  2502
}
dvander@2226
  2503
dvander@2226
  2504
bool JITX86::InitializeJIT()
dvander@2226
  2505
{
dvander@2226
  2506
	jitoffs_t offs;
dvander@2226
  2507
	JitWriter writer, *jit;
dvander@2226
  2508
dvander@2226
  2509
	g_pCodeCache = KE_CreateCodeCache();
dvander@2226
  2510
dvander@2226
  2511
	jit = &writer;
dvander@2226
  2512
	
dvander@2226
  2513
	/* Build the genarray intrinsic */
dvander@2226
  2514
	jit->outbase = NULL;
dvander@2226
  2515
	jit->outptr = NULL;
dvander@2226
  2516
	WriteIntrinsic_GenArray(jit);
dvander@2226
  2517
	m_pJitGenArray = Knight::KE_AllocCode(g_pCodeCache, jit->get_outputpos());
dvander@2226
  2518
	jit->outbase = (jitcode_t)m_pJitGenArray;
dvander@2226
  2519
	jit->outptr = jit->outbase;
dvander@2226
  2520
	WriteIntrinsic_GenArray(jit);
dvander@2226
  2521
dvander@2226
  2522
	/* Build the entry point */
dvander@2226
  2523
	writer = JitWriter();
dvander@2226
  2524
	jit->outbase = NULL;
dvander@2226
  2525
	jit->outptr = NULL;
dvander@2226
  2526
	Write_Execute_Function(jit);
dvander@2226
  2527
	m_pJitEntry = Knight::KE_AllocCode(g_pCodeCache, jit->get_outputpos());
dvander@2226
  2528
	jit->outbase = (jitcode_t)m_pJitEntry;
dvander@2226
  2529
	jit->outptr = jit->outbase;
dvander@2226
  2530
	offs = Write_Execute_Function(jit);
dvander@2226
  2531
	m_pJitReturn = (uint8_t *)m_pJitEntry + offs;
dvander@2226
  2532
dvander@2226
  2533
	return true;
dvander@2226
  2534
}
dvander@2226
  2535
dvander@2226
  2536
void JITX86::ShutdownJIT()
dvander@2226
  2537
{
dvander@2226
  2538
	KE_DestroyCodeCache(g_pCodeCache);
dvander@2226
  2539
}
dvander@2226
  2540
dvander@2226
  2541
JitFunction *JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err)
dvander@2226
  2542
{
dvander@2226
  2543
	CompData *data = (CompData *)prt->m_pCo;
dvander@2226
  2544
	sp_plugin_t *plugin = data->plugin;
dvander@2226
  2545
dvander@2226
  2546
	uint8_t *code = plugin->pcode + pcode_offs;
dvander@2226
  2547
	uint8_t *end_code = plugin->pcode + plugin->pcode_size;
dvander@2226
  2548
dvander@2226
  2549
	assert(FuncLookup(data, pcode_offs) == 0);
dvander@2226
  2550
dvander@2226
  2551
	if (code >= end_code || *(cell_t *)code != OP_PROC)
dvander@2226
  2552
	{
dvander@2226
  2553
		*err = SP_ERROR_INVALID_INSTRUCTION;
dvander@2226
  2554
		return NULL;
dvander@2226
  2555
	}
dvander@2226
  2556
dvander@2226
  2557
#if defined _DEBUG
dvander@2226
  2558
	g_engine1.GetDebugHook()->OnDebugSpew("Compiling function %s::%s", prt->m_pPlugin->name, find_func_name(prt->m_pPlugin, pcode_offs));
dvander@2226
  2559
#endif
dvander@2226
  2560
dvander@2226
  2561
	code += sizeof(cell_t);
dvander@2226
  2562
ds@1952
  2563
	OPCODE op;
dvander@2226
  2564
	uint32_t code_size;
dvander@2226
  2565
	cell_t *cip, *end_cip;
dvander@2226
  2566
	JitWriter writer, *jit;
dvander@2226
  2567
dvander@2226
  2568
	jit = &writer;
dvander@2226
  2569
	cip = (cell_t *)code;
dvander@2226
  2570
	end_cip = (cell_t *)end_code;
ds@1952
  2571
	writer.data = data;
dvander@2226
  2572
	writer.inbase = cip;
ds@1952
  2573
	writer.outptr = NULL;
ds@1952
  2574
	writer.outbase = NULL;
dvander@2226
  2575
	data->cur_func = pcode_offs;
dvander@2226
  2576
ds@1952
  2577
jit_rewind:
dvander@2226
  2578
	data->num_thunks = 0;
ds@1952
  2579
	writer.inptr = writer.inbase;
dvander@2226
  2580
dvander@2226
  2581
	WriteOp_Proc(jit);
ds@1952
  2582
ds@1952
  2583
	/* Actual code generation! */
ds@1952
  2584
	if (writer.outbase == NULL)
ds@1952
  2585
	{
ds@1952
  2586
		/* First Pass - find codesize and resolve relocation */
dvander@2226
  2587
		jitoffs_t jpcode_offs;
ds@1952
  2588
		jitoffs_t native_offs;
ds@1952
  2589
dvander@2226
  2590
		for (; writer.inptr < end_cip;)
ds@1952
  2591
		{
dvander@2226
  2592
			op = (OPCODE)writer.peek_cell();
dvander@2226
  2593
dvander@2226
  2594
			/* If we hit another function, we must stop. */
dvander@2226
  2595
			if (op == OP_PROC || op == OP_ENDPROC)
dvander@2226
  2596
			{
dvander@2226
  2597
				break;
dvander@2226
  2598
			}
dvander@2226
  2599
ds@1952
  2600
			/* Store the native offset into the rebase memory.
ds@1952
  2601
			 * This large chunk of memory lets us do an instant lookup
ds@1952
  2602
			 * based on an original pcode offset.
ds@1952
  2603
			 */
dvander@2226
  2604
			jpcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - plugin->pcode);
ds@1952
  2605
			native_offs = jit->get_outputpos();
dvander@2226
  2606
			*((jitoffs_t *)(data->rebase + jpcode_offs)) = native_offs;
dvander@2226
  2607
dvander@2226
  2608
			/* Read past the opcode. */
dvander@2226
  2609
			writer.read_cell();
ds@1952
  2610
ds@1952
  2611
			/* Patch the floating point natives with our opcodes */
ds@1952
  2612
			if (op == OP_SYSREQ_N)
ds@1952
  2613
			{
ds@1952
  2614
				cell_t idx = writer.read_cell();
ds@1952
  2615
				if (data->jit_float_table[idx].found)
ds@1952
  2616
				{
ds@1952
  2617
					writer.inptr -= 2;
ds@1952
  2618
					*(writer.inptr++) = data->jit_float_table[idx].index;
ds@1952
  2619
					*(writer.inptr++) = OP_NOP;
ds@1952
  2620
					*(writer.inptr++) = OP_NOP;
ds@1952
  2621
					op = (OPCODE)data->jit_float_table[idx].index;
dvander@2093
  2622
				}
dvander@2093
  2623
				else
dvander@2093
  2624
				{
ds@1952
  2625
					writer.inptr--;
ds@1952
  2626
				}
ds@1952
  2627
			}
ds@1952
  2628
			switch (op)
ds@1952
  2629
			{
ds@1952
  2630
				#include "opcode_switch.inc"
ds@1952
  2631
			}
ds@1952
  2632
			/* Check for errors.  This should only happen in the first pass. */
ds@1952
  2633
			if (data->error_set != SP_ERROR_NONE)
ds@1952
  2634
			{
ds@1952
  2635
				*err = data->error_set;
dvander@2226
  2636
				return NULL;
ds@1952
  2637
			}
ds@1952
  2638
		}
dvander@2226
  2639
dvander@2226
  2640
		/* Write these last because error jumps should be predicted forwardly (not taken) */
ds@1952
  2641
		WriteErrorRoutines(data, jit);
ds@1952
  2642
dvander@2226
  2643
		/* Build thunk tables */
dvander@2226
  2644
		if (data->num_thunks > data->max_thunks)
dvander@2226
  2645
		{
dvander@2226
  2646
			data->max_thunks = data->num_thunks;
dvander@2226
  2647
			data->thunks = (call_thunk_t *)realloc(
dvander@2226
  2648
				data->thunks,
dvander@2226
  2649
				data->max_thunks * sizeof(call_thunk_t));
dvander@2226
  2650
		}
dvander@2226
  2651
dvander@2226
  2652
		/* Write the thunk offsets.
dvander@2226
  2653
		 * :TODO: we can emit all but one call to Write_CallThunk().
dvander@2226
  2654
		 */
dvander@2226
  2655
		for (unsigned int i = 0; i < data->num_thunks; i++)
dvander@2226
  2656
		{
dvander@2226
  2657
			data->thunks[i].thunk_addr = jit->get_outputpos();
dvander@2226
  2658
			Write_CallThunk(jit, 0, 0);
dvander@2226
  2659
		}
dvander@2226
  2660
dvander@2226
  2661
		/**
dvander@2226
  2662
		 * I don't understand the purpose of this code.
dvander@2226
  2663
		 * Why do we want to know about the last opcode?
dvander@2226
  2664
		 * It should already have gotten written.
dvander@2226
  2665
		 */
dvander@2226
  2666
		#if 0
ds@1952
  2667
		/* Write the final CIP to the last position in the reloc array */
ds@1952
  2668
		pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code);
ds@1952
  2669
		native_offs = jit->get_outputpos();
ds@1952
  2670
		*((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs;
dvander@2226
  2671
		#endif
ds@1952
  2672
ds@1952
  2673
		/* the total codesize is now known! */
dvander@2226
  2674
		code_size = writer.get_outputpos();
dvander@2226
  2675
		writer.outbase = (jitcode_t)Knight::KE_AllocCode(g_pCodeCache, code_size);
ds@1952
  2676
		writer.outptr = writer.outbase;
dvander@2226
  2677
dvander@2226
  2678
		/* go back for second pass */
ds@1952
  2679
		goto jit_rewind;
dvander@2093
  2680
	}
dvander@2093
  2681
	else
dvander@2093
  2682
	{
ds@1952
  2683
		/*******
dvander@2226
  2684
		 * SECOND PASS - write opcode info
ds@1952
  2685
		 *******/
dvander@2226
  2686
		for (; writer.inptr < end_cip;)
ds@1952
  2687
		{
ds@1952
  2688
			op = (OPCODE)writer.read_cell();
dvander@2226
  2689
dvander@2226
  2690
			/* If we hit another function, we must stop. */
dvander@2226
  2691
			if (op == OP_PROC || op == OP_ENDPROC)
dvander@2226
  2692
			{
dvander@2226
  2693
				break;
dvander@2226
  2694
			}
dvander@2226
  2695
ds@1952
  2696
			switch (op)
ds@1952
  2697
			{
ds@1952
  2698
				#include "opcode_switch.inc"
ds@1952
  2699
			}
ds@1952
  2700
		}
dvander@2226
  2701
dvander@2226
  2702
		/* Write these last because error jumps should be predicted as not taken (forward) */
ds@1952
  2703
		WriteErrorRoutines(data, jit);
ds@1952
  2704
dvander@2226
  2705
		/* Write the thunk offsets. */
dvander@2226
  2706
		for (unsigned int i = 0; i < data->num_thunks; i++)
ds@1952
  2707
		{
dvander@2226
  2708
			Write_CallThunk(jit, data->thunks[i].patch_addr, data->thunks[i].pcode_offs);
ds@1952
  2709
		}
ds@1952
  2710
	}
ds@1952
  2711
dvander@2226
  2712
	plugin->prof_flags = data->profile;
dvander@2226
  2713
dvander@2226
  2714
	*err = SP_ERROR_NONE;
dvander@2226
  2715
dvander@2226
  2716
	JitFunction *fn;
dvander@2226
  2717
	uint32_t func_idx;
dvander@2226
  2718
	
dvander@2226
  2719
	fn = new JitFunction(writer.outbase, pcode_offs);
dvander@2226
  2720
	func_idx = prt->AddJittedFunction(fn);
dvander@2226
  2721
	*(cell_t *)(data->rebase + pcode_offs) = func_idx;
dvander@2226
  2722
dvander@2226
  2723
	return fn;
dvander@2226
  2724
}
dvander@2226
  2725
dvander@2226
  2726
void JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx)
dvander@2226
  2727
{
ds@1952
  2728
	tracker_t *trk = new tracker_t;
dvander@2226
  2729
ds@1952
  2730
	ctx->vm[JITVARS_TRACKER] = trk;
dvander@2226
  2731
	ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */
dvander@2193
  2732
	ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler();
dvander@2226
  2733
	ctx->vm[JITVARS_PLUGIN] = runtime->m_pPlugin;
dvander@2226
  2734
ds@1952
  2735
	trk->pBase = (ucell_t *)malloc(1024);
ds@1952
  2736
	trk->pCur = trk->pBase;
ds@1952
  2737
	trk->size = 1024 / sizeof(cell_t);
ds@1952
  2738
}
ds@1952
  2739
ds@1952
  2740
SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
ds@1952
  2741
{
ds@1952
  2742
	JitWriter jw;
ds@1952
  2743
	JitWriter *jit = &jw;
ds@1952
  2744
ds@1952
  2745
	jw.outbase = NULL;
ds@1952
  2746
	jw.outptr = NULL;
ds@1952
  2747
	jw.data = NULL;
ds@1952
  2748
ds@1952
  2749
	/* First pass, calculate size */
ds@1952
  2750
rewind:
ds@1952
  2751
	/* Align the stack to 16 bytes */
ds@1952
  2752
	//push ebx
ds@1952
  2753
	//push edi
ds@1952
  2754
	//push esi
ds@1952
  2755
	//mov edi, [esp+16]	;store ctx
ds@1952
  2756
	//mov esi, [esp+20]	;store params
ds@1952
  2757
	//mov ebx, esp
ds@1952
  2758
	//and esp, 0xFFFFFF0
ds@1952
  2759
	//sub esp, 4
ds@1952
  2760
	IA32_Push_Reg(jit, REG_EBX);
ds@1952
  2761
	IA32_Push_Reg(jit, REG_EDI);
ds@1952
  2762
	IA32_Push_Reg(jit, REG_ESI);
ds@1952
  2763
	IA32_Mov_Reg_Esp_Disp8(jit, REG_EDI, 16);
ds@1952
  2764
	IA32_Mov_Reg_Esp_Disp8(jit, REG_ESI, 20);
ds@1952
  2765
	IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
ds@1952
  2766
	IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
ds@1952
  2767
	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
ds@1952
  2768
ds@1952
  2769
	//push pData		;push pData
ds@1952
  2770
	//push esi			;push params
ds@1952
  2771
	//push edi			;push ctx
ds@1952
  2772
	//call [callback]	;invoke the meta-callback
ds@1952
  2773
	//mov esp, ebx		;restore the stack
ds@1952
  2774
	//pop esi			;restore esi
ds@1952
  2775
	//pop edi			;restore edi
ds@1952
  2776
	//pop ebx			;restore ebx
ds@1952
  2777
	//ret				;return
ds@1952
  2778
	IA32_Push_Imm32(jit, (jit_int32_t)pData);
ds@1952
  2779
	IA32_Push_Reg(jit, REG_ESI);
ds@1952
  2780
	IA32_Push_Reg(jit, REG_EDI);
ds@1952
  2781
	uint32_t call = IA32_Call_Imm32(jit, 0);
ds@1952
  2782
	IA32_Write_Jump32_Abs(jit, call, (void *)callback);
ds@1952
  2783
	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
ds@1952
  2784
	IA32_Pop_Reg(jit, REG_ESI);
ds@1952
  2785
	IA32_Pop_Reg(jit, REG_EDI);
ds@1952
  2786
	IA32_Pop_Reg(jit, REG_EBX);
ds@1952
  2787
	IA32_Return(jit);
ds@1952
  2788
ds@1952
  2789
	if (jw.outbase == NULL)
ds@1952
  2790
	{
ds@1952
  2791
		/* Second pass: Actually write */
dvander@2226
  2792
		jw.outbase = (jitcode_t)KE_AllocCode(g_pCodeCache, jw.get_outputpos());
ds@1952
  2793
		if (!jw.outbase)
ds@1952
  2794
		{
ds@1952
  2795
			return NULL;
ds@1952
  2796
		}
ds@1952
  2797
		jw.outptr = jw.outbase;
ds@1952
  2798
	
ds@1952
  2799
		goto rewind;
ds@1952
  2800
	}
ds@1952
  2801
ds@1952
  2802
	return (SPVM_NATIVE_FUNC)jw.outbase;
ds@1952
  2803
}
ds@1952
  2804
ds@1952
  2805
void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
ds@1952
  2806
{
dvander@2226
  2807
	KE_FreeCode(g_pCodeCache, (void *)func);
ds@1952
  2808
}
ds@1952
  2809
dvander@2193
  2810
ICompilation *JITX86::StartCompilation()
ds@1952
  2811
{
ds@1952
  2812
	CompData *data = new CompData;
dvander@2193
  2813
dvander@2193
  2814
	data->jit_float_table = NULL;
dvander@2193
  2815
dvander@2193
  2816
	return data;
dvander@2193
  2817
}
dvander@2193
  2818
dvander@2193
  2819
void CompData::SetRuntime(BaseRuntime *runtime)
dvander@2193
  2820
{
dvander@2193
  2821
	plugin = runtime->m_pPlugin;
dvander@2193
  2822
dvander@2226
  2823
	uint32_t max_natives = plugin->num_natives;
ds@1952
  2824
dvander@2193
  2825
	this->runtime = runtime;
dvander@2226
  2826
	this->plugin = runtime->m_pPlugin;
dvander@2193
  2827
dvander@2193
  2828
	inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
dvander@2193
  2829
	error_set = SP_ERROR_NONE;
dvander@2193
  2830
dvander@2193
  2831
	jit_float_table = new floattbl_t[max_natives];
ds@1952
  2832
	for (uint32_t i=0; i<max_natives; i++)
ds@1952
  2833
	{
dvander@2226
  2834
		const char *name = plugin->natives[i].name;
ds@1952
  2835
		if (!strcmp(name, "FloatAbs"))
ds@1952
  2836
		{
dvander@2193
  2837
			jit_float_table[i].found = true;
dvander@2193
  2838
			jit_float_table[i].index = OP_FABS;
dvander@2226
  2839
		} 
dvander@2226
  2840
		else if (!strcmp(name, "FloatAdd")) 
dvander@2226
  2841
		{
dvander@2193
  2842
			jit_float_table[i].found = true;
dvander@2193
  2843
			jit_float_table[i].index = OP_FLOATADD;
dvander@2226
  2844
		} 
dvander@2226
  2845
		else if (!strcmp(name, "FloatSub")) 
dvander@2226
  2846
		{
dvander@2193
  2847
			jit_float_table[i].found = true;
dvander@2193
  2848
			jit_float_table[i].index = OP_FLOATSUB;
dvander@2226
  2849
		} 
dvander@2226
  2850
		else if (!strcmp(name, "FloatMul")) 
dvander@2226
  2851
		{
dvander@2193
  2852
			jit_float_table[i].found = true;
dvander@2193
  2853
			jit_float_table[i].index = OP_FLOATMUL;
dvander@2226
  2854
		} 
dvander@2226
  2855
		else if (!strcmp(name, "FloatDiv")) 
dvander@2226
  2856
		{
dvander@2193
  2857
			jit_float_table[i].found = true;
dvander@2193
  2858
			jit_float_table[i].index = OP_FLOATDIV;
dvander@2226
  2859
		} 
dvander@2226
  2860
		else if (!strcmp(name, "float")) 
dvander@2226
  2861
		{
dvander@2193
  2862
			jit_float_table[i].found = true;
dvander@2193
  2863
			jit_float_table[i].index = OP_FLOAT;
dvander@2226
  2864
		} 
dvander@2226
  2865
		else if (!strcmp(name, "FloatCompare")) 
dvander@2226
  2866
		{
dvander@2193
  2867
			jit_float_table[i].found = true;
dvander@2193
  2868
			jit_float_table[i].index = OP_FLOATCMP;
dvander@2226
  2869
		} 
dvander@2226
  2870
		else if (!strcmp(name, "RoundToZero")) 
dvander@2226
  2871
		{
dvander@2193
  2872
			jit_float_table[i].found = true;
dvander@2193
  2873
			jit_float_table[i].index = OP_RND_TO_ZERO;
dvander@2226
  2874
		} 
dvander@2226
  2875
		else if (!strcmp(name, "RoundToCeil")) 
dvander@2226
  2876
		{
dvander@2193
  2877
			jit_float_table[i].found = true;
dvander@2193
  2878
			jit_float_table[i].index = OP_RND_TO_CEIL;
dvander@2226
  2879
		} 
dvander@2226
  2880
		else if (!strcmp(name, "RoundToFloor")) 
dvander@2226
  2881
		{
dvander@2193
  2882
			jit_float_table[i].found = true;
dvander@2193
  2883
			jit_float_table[i].index = OP_RND_TO_FLOOR;
dvander@2226
  2884
		} 
dvander@2226
  2885
		else if (!strcmp(name, "RoundToNearest")) 
dvander@2226
  2886
		{
dvander@2193
  2887
			jit_float_table[i].found = true;
dvander@2193
  2888
			jit_float_table[i].index = OP_RND_TO_NEAREST;
ds@1952
  2889
		}
ds@1952
  2890
	}
dvander@2226
  2891
dvander@2226
  2892
	/* We need a relocation table.  This is the relocation table we'll use for jumps 
dvander@2226
  2893
	 * and calls alike.  One extra cell for final CIP.
dvander@2226
  2894
	 */
dvander@2226
  2895
	this->rebase = (uint8_t *)engine->BaseAlloc(plugin->pcode_size + sizeof(cell_t));
dvander@2226
  2896
	memset(this->rebase, 0, plugin->pcode_size + sizeof(cell_t));
dvander@2193
  2897
}
dvander@2193
  2898
dvander@2193
  2899
ICompilation *JITX86::StartCompilation(BaseRuntime *runtime)
dvander@2193
  2900
{
dvander@2193
  2901
	CompData *data = new CompData;
dvander@2193
  2902
dvander@2193
  2903
	data->SetRuntime(runtime);
ds@1952
  2904
ds@1952
  2905
	return data;
ds@1952
  2906
}
ds@1952
  2907
dvander@2193
  2908
void CompData::Abort()
ds@1952
  2909
{
dvander@2193
  2910
	if (rebase)
ds@1952
  2911
	{
dvander@2193
  2912
		engine->BaseFree(rebase);
ds@1952
  2913
	}
dvander@2226
  2914
	delete [] thunks;
dvander@2193
  2915
	delete [] jit_float_table;
dvander@2193
  2916
	delete this;
dvander@2193
  2917
}
dvander@2193
  2918
dvander@2193
  2919
void JITX86::FreeContextVars(sp_context_t *ctx)
dvander@2193
  2920
{
dvander@2193
  2921
	free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
dvander@2193
  2922
	delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
ds@1952
  2923
}
ds@1952
  2924
dvander@2193
  2925
bool CompData::SetOption(const char *key, const char *val)
dvander@2193
  2926
{
ds@1952
  2927
	if (strcmp(key, SP_JITCONF_DEBUG) == 0)
ds@1952
  2928
	{
ds@1952
  2929
		return true;
ds@1952
  2930
	}
ds@1952
  2931
	else if (strcmp(key, SP_JITCONF_PROFILE) == 0)
ds@1952
  2932
	{
dvander@2193
  2933
		profile = atoi(val);
ds@1952
  2934
ds@1952
  2935
		/** Callbacks must be profiled to profile functions! */
dvander@2193
  2936
		if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
ds@1952
  2937
		{
dvander@2193
  2938
			profile |= SP_PROF_CALLBACKS;
ds@1952
  2939
		}
ds@1952
  2940
ds@1952
  2941
		return true;
ds@1952
  2942
	}
ds@1952
  2943
ds@1952
  2944
	return false;
ds@1952
  2945
}
ds@1952
  2946
dvander@2226
  2947
void *JITX86::GetGenArrayIntrinsic()
dvander@2226
  2948
{
dvander@2226
  2949
	return m_pJitGenArray;
dvander@2226
  2950
}
dvander@2226
  2951
dvander@2226
  2952
void *JITX86::GetReturnPoint()
dvander@2226
  2953
{
dvander@2226
  2954
	return m_pJitReturn;
dvander@2226
  2955
}
dvander@2226
  2956
dvander@2226
  2957
void *JITX86::GetRoundingTable()
dvander@2226
  2958
{
dvander@2226
  2959
	return m_RoundTable;
dvander@2226
  2960
}
dvander@2226
  2961
dvander@2226
  2962
typedef int (*JIT_EXECUTE)(cell_t *vars, void *addr);
dvander@2226
  2963
int JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result)
dvander@2226
  2964
{
dvander@2226
  2965
	int err;
dvander@2226
  2966
	JIT_EXECUTE pfn;
dvander@2226
  2967
	sp_context_t *ctx;
dvander@2226
  2968
	cell_t vars[AMX_NUM_INFO_VARS];
dvander@2226
  2969
dvander@2226
  2970
	ctx = runtime->GetBaseContext()->GetCtx();
dvander@2226
  2971
dvander@2226
  2972
	vars[0] = ctx->sp;
dvander@2226
  2973
	vars[1] = ctx->hp;
dvander@2226
  2974
	vars[2] = (cell_t)result;
dvander@2226
  2975
	vars[3] = (cell_t)ctx;
dvander@2226
  2976
	vars[4] = (cell_t)(runtime->m_pPlugin->memory + runtime->m_pPlugin->mem_size);
dvander@2226
  2977
	vars[5] = fn->GetPCodeAddress();
dvander@2226
  2978
	vars[6] = runtime->m_pPlugin->data_size;
dvander@2226
  2979
	vars[7] = (cell_t)(runtime->m_pPlugin->memory);
dvander@2226
  2980
	/* vars[8] will be set to ESP */
dvander@2226
  2981
dvander@2226
  2982
	pfn = (JIT_EXECUTE)m_pJitEntry;
dvander@2226
  2983
	err = pfn(vars, fn->GetEntryAddress());
dvander@2226
  2984
dvander@2226
  2985
	ctx->hp = vars[1];
dvander@2226
  2986
	ctx->err_cip = vars[5];
dvander@2226
  2987
dvander@2226
  2988
	return err;
dvander@2226
  2989
}
dvander@2226
  2990
dvander@2226
  2991
void *JITX86::AllocCode(size_t size)
dvander@2226
  2992
{
dvander@2226
  2993
	return Knight::KE_AllocCode(g_pCodeCache, size);
dvander@2226
  2994
}
dvander@2226
  2995
dvander@2226
  2996
void JITX86::FreeCode(void *code)
dvander@2226
  2997
{
dvander@2226
  2998
	KE_FreeCode(g_pCodeCache, code);
dvander@2226
  2999
}