sourcepawn/vm/jit/x86/opcode_helpers.cpp
author David Anderson <dvander@alliedmods.net>
Tue Oct 10 16:39:55 2006 +0000 (2006-10-10)
changeset 107 9c818dbf8c69
parent 105 98aaeb6ee956
child 112 ae7af70e0f27
permissions -rw-r--r--
small touch-ups
dvander@70
     1
#include <limits.h>
dvander@70
     2
#include <string.h>
dvander@70
     3
#include "jit_x86.h"
dvander@70
     4
#include "opcode_helpers.h"
dvander@70
     5
#include "x86_macros.h"
dvander@70
     6
dvander@70
     7
int OpAdvTable[OP_NUM_OPCODES];
dvander@70
     8
dvander@105
     9
#define NUM_INFO_PARAMS	7
dvander@105
    10
dvander@93
    11
jitoffs_t Write_Execute_Function(JitWriter *jit)
dvander@73
    12
{
dvander@73
    13
	/** 
dvander@73
    14
	 * The variables we're passed in:
dvander@73
    15
	 *  sp_context_t *ctx, uint32_t code_idx, cell_t *result
dvander@73
    16
	 */
dvander@73
    17
dvander@74
    18
	/**
dvander@74
    19
	 * !NOTE!
dvander@74
    20
	 * Currently, we do not accept ctx->frm as the new frame pointer.
dvander@74
    21
	 * Instead, we copy the frame from the stack pointer.
dvander@74
    22
	 * This is because we do not support resuming or sleeping!
dvander@74
    23
	 */
dvander@73
    24
dvander@74
    25
	//push ebp
dvander@74
    26
	//mov ebp, esp
dvander@74
    27
	IA32_Push_Reg(jit, REG_EBP);
dvander@74
    28
	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
dvander@74
    29
dvander@74
    30
	//push esi
dvander@74
    31
	//push edi
dvander@74
    32
	//push ebx
dvander@74
    33
	IA32_Push_Reg(jit, REG_ESI);
dvander@74
    34
	IA32_Push_Reg(jit, REG_EDI);
dvander@74
    35
	IA32_Push_Reg(jit, REG_EBX);
dvander@74
    36
dvander@105
    37
	//sub esp, 4*n	- reserve info array
dvander@74
    38
	//mov esi, esp	- save info pointer
dvander@105
    39
	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
dvander@74
    40
	IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
dvander@74
    41
dvander@83
    42
	/* Initial memory setup */
dvander@83
    43
	//mov eax, [ebp+16]		- get result pointer
dvander@83
    44
	//mov [esi+8], eax		- store into info pointer
dvander@74
    45
	//mov eax, [ebp+8]		- get context
dvander@74
    46
	//mov [esi+12], eax		- store context into info pointer
dvander@74
    47
	//mov ecx, [eax+<offs>]	- get heap pointer
dvander@74
    48
	//mov [esi+4], ecx		- store heap into info pointer
dvander@105
    49
	//mov ebp, [eax+<offs>]	- get data pointer
dvander@83
    50
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
dvander@83
    51
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
dvander@74
    52
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
dvander@83
    53
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
dvander@74
    54
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
dvander@83
    55
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
dvander@74
    56
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data));
dvander@74
    57
dvander@83
    58
	/* Frame setup */
dvander@105
    59
	//mov edi, [eax+<offs>]	- get stack pointer
dvander@105
    60
	//add edi, ebp			- relocate to data section
dvander@105
    61
	//mov ebx, edi			- copy sp to frm
dvander@75
    62
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
dvander@105
    63
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@75
    64
	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
dvander@75
    65
dvander@83
    66
	/* Info memory setup */
dvander@105
    67
	//mov ecx, [eax+<offs>] - copy memsize to temp var
dvander@105
    68
	//mov [esi+x], ecx		- store unrelocated
dvander@105
    69
	//add ecx, ebp			- relocate
dvander@105
    70
	//mov [esi+x], ecx		- store relocated
dvander@83
    71
	//mov ecx, [eax+<offs>] - get heap low
dvander@83
    72
	//mov [esi+20], ecx		- store heap low into info pointer
dvander@105
    73
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
dvander@105
    74
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP_U);
dvander@105
    75
	IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
dvander@83
    76
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
dvander@83
    77
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, heapbase));
dvander@83
    78
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAPLOW);
dvander@75
    79
dvander@83
    80
	/* Remaining needed vars */
dvander@105
    81
	//mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
dvander@105
    82
	//add ecx, [eax+<offs>]   - add code base to index
dvander@105
    83
	IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
dvander@93
    84
	IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
dvander@74
    85
dvander@74
    86
	/* by now, everything is set up, so we can call into the plugin */
dvander@74
    87
	//call ecx
dvander@86
    88
	IA32_Call_Reg(jit, REG_ECX);
dvander@74
    89
dvander@74
    90
	/* if the code flow gets to here, there was a normal return */
dvander@105
    91
	//mov ecx, [esi+8]		- get retval pointer
dvander@105
    92
	//mov [ecx], eax		- store retval from PRI
dvander@74
    93
	//mov eax, SP_ERR_NONE	- set no error
dvander@105
    94
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
dvander@105
    95
	IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
dvander@74
    96
	IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERR_NONE);
dvander@74
    97
dvander@75
    98
	/* save where error checking/halting functions should go to */
dvander@105
    99
	jitoffs_t offs_return = jit->get_outputpos();
dvander@105
   100
	//mov esp, esi			- restore stack pointer
dvander@105
   101
	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
dvander@74
   102
dvander@105
   103
	/* _FOR NOW_ ...
dvander@105
   104
	 * We are going to restore SP, HP, and FRM for now.  This is for 
dvander@105
   105
     * debugging only, to check for alignment errors.  As such:
dvander@105
   106
	 * :TODO: probably remove this.
dvander@74
   107
	 */
dvander@105
   108
	//mov ecx, [esi+context]
dvander@105
   109
	//sub edi, ebp
dvander@105
   110
	//mov edx, [esi+heap]
dvander@105
   111
	//mov [ecx+sp], edi
dvander@105
   112
	//mov [ecx+hp], edx
dvander@105
   113
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
dvander@105
   114
	IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
dvander@105
   115
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
dvander@105
   116
	IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
dvander@105
   117
	IA32_Mov_Rm_Reg(jit, REG_ECX, REG_EDX, MOD_REG);
dvander@74
   118
dvander@105
   119
	//add esp, 4*NUM_INFO_PARAMS
dvander@74
   120
	//pop ebx
dvander@74
   121
	//pop edi
dvander@74
   122
	//pop esi
dvander@74
   123
	//pop ebp
dvander@74
   124
	//ret
dvander@105
   125
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
dvander@74
   126
	IA32_Pop_Reg(jit, REG_EBX);
dvander@74
   127
	IA32_Pop_Reg(jit, REG_EDI);
dvander@74
   128
	IA32_Pop_Reg(jit, REG_ESI);
dvander@74
   129
	IA32_Pop_Reg(jit, REG_EBP);
dvander@74
   130
	IA32_Return(jit);
dvander@74
   131
dvander@74
   132
	return offs_return;
dvander@73
   133
}
dvander@73
   134
dvander@86
   135
void Write_BreakDebug(JitWriter *jit)
dvander@86
   136
{
dvander@86
   137
	//push ecx
dvander@86
   138
	//mov ecx, [esi+ctx]
dvander@86
   139
	//cmp [ecx+dbreak], 0
dvander@86
   140
	//jnz :nocall
dvander@86
   141
	IA32_Push_Reg(jit, AMX_REG_TMP);
dvander@86
   142
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
faluco@97
   143
	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
dvander@86
   144
	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
dvander@86
   145
dvander@86
   146
	//pushad
dvander@86
   147
	IA32_Pushad(jit);
dvander@86
   148
dvander@86
   149
	//push [esi+frm]
dvander@86
   150
	//push [ecx+context]
dvander@86
   151
	//mov ecx, [ecx+dbreak]
dvander@86
   152
	//call ecx
dvander@86
   153
	//add esp, 8
dvander@86
   154
	//popad
faluco@97
   155
	IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
dvander@86
   156
	IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context));
dvander@86
   157
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
dvander@86
   158
	IA32_Call_Reg(jit, AMX_REG_TMP);
dvander@86
   159
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
dvander@86
   160
	IA32_Popad(jit);
dvander@86
   161
dvander@86
   162
	//:nocall
dvander@86
   163
	IA32_Send_Jump8_Here(jit, jmp);
dvander@86
   164
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG);
dvander@86
   165
	IA32_Return(jit);
dvander@86
   166
}
dvander@86
   167
dvander@105
   168
void Write_SetError(JitWriter *jit, bool always_inline, int error)
dvander@75
   169
{
dvander@75
   170
	CompData *data = (CompData *)jit->data;
dvander@75
   171
dvander@75
   172
	/* These are so small that we always inline them! */
dvander@75
   173
	//mov eax, <error>
dvander@75
   174
	//jmp [...jit_return]
dvander@75
   175
	IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
dvander@75
   176
	jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
dvander@75
   177
	IA32_Write_Jump32(jit, jmp, data->jit_return);
dvander@75
   178
}
dvander@75
   179
faluco@81
   180
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
faluco@81
   181
{
faluco@81
   182
	//test reg, reg
dvander@105
   183
	//jz :error
faluco@81
   184
	IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
dvander@105
   185
	IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
dvander@105
   186
}
dvander@105
   187
dvander@105
   188
void Write_CheckHeap_Min(JitWriter *jit)
dvander@105
   189
{
dvander@105
   190
	/* Check if the stack went beyond the heap low.
dvander@105
   191
	 * This usually means there was a compiler error.
dvander@105
   192
	 * NOTE: Special optimization here.
dvander@105
   193
	 * The heap low is always known ahead of time! :)
dvander@105
   194
	 */
dvander@105
   195
	CompData *data = (CompData *)jit->data;
dvander@105
   196
	//cmp [esi+info.heap], <heaplow>
dvander@105
   197
	//jb :error
dvander@105
   198
	IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
dvander@105
   199
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
dvander@105
   200
}
faluco@81
   201
dvander@105
   202
void Write_CheckHeap_Low(JitWriter *jit)
dvander@105
   203
{
dvander@105
   204
	/* Check if the heap is trying to grow beyond the stack.
dvander@105
   205
	 */
dvander@105
   206
	//mov ecx, [esi+info.heap]
dvander@105
   207
	//lea ecx, [ebp+ecx+STACK_MARGIN]
dvander@105
   208
	//cmp ecx, edi
dvander@105
   209
	//ja :error		; I think this is right
dvander@105
   210
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   211
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
dvander@105
   212
	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
dvander@105
   213
	IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
faluco@81
   214
}
dvander@105
   215
dvander@105
   216
void Write_CheckStack_Min(JitWriter *jit)
dvander@105
   217
{
dvander@105
   218
	/* Check if the stack went beyond the stack top
dvander@105
   219
	 * This usually means there was a compiler error.
dvander@105
   220
	 */
dvander@105
   221
	//cmp edi, [esi+info.stacktop]
dvander@105
   222
	//jae :error
dvander@105
   223
	IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
dvander@105
   224
	IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
dvander@105
   225
}
dvander@105
   226
dvander@105
   227
void Write_CheckStack_Low(JitWriter *jit)
dvander@105
   228
{
dvander@105
   229
	/* Check if the stack went beyond the heap boundary.
dvander@105
   230
	 * Unfortunately this one isn't as quick as the other check.
dvander@105
   231
	 * The stack margin check is important for sysreq.n having space.
dvander@105
   232
	 */
dvander@105
   233
	//mov ecx, [esi+info.heap]
dvander@105
   234
	//lea ecx, [ebp+ecx+STACK_MARGIN]
dvander@105
   235
	//cmp edi, ecx
dvander@105
   236
	//jb :error		; I think this is right
dvander@105
   237
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   238
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
dvander@105
   239
	IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
dvander@105
   240
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
dvander@105
   241
}
dvander@105
   242
dvander@105
   243
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
dvander@75
   244
{
dvander@75
   245
	CompData *data = (CompData *)jit->data;
dvander@75
   246
dvander@75
   247
	/* :TODO: Should this be checking for below heaplow?
dvander@75
   248
	 * The old JIT did not.
dvander@75
   249
	 */
dvander@75
   250
dvander@75
   251
	bool call = false;
dvander@75
   252
	if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
dvander@75
   253
	{
dvander@75
   254
		/* If we're not in the initial generation phase,
dvander@75
   255
		 * Write a call to the actual routine instead.
dvander@75
   256
		 */
dvander@105
   257
		if ((reg == REG_EAX) && data->jit_verify_addr_eax)
dvander@75
   258
		{
dvander@75
   259
			jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@105
   260
			IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
dvander@105
   261
			return;
dvander@105
   262
		} else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
dvander@105
   263
			jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@105
   264
			IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
dvander@75
   265
			return;
dvander@75
   266
		}
dvander@75
   267
		call = true;
dvander@75
   268
	}
dvander@75
   269
dvander@105
   270
	/** 
dvander@105
   271
	 * :TODO: If we can't find a nicer way of doing this,
dvander@105
   272
	 *  then scrap it on high optimizations.  The second portion is not needed at all!
dvander@105
   273
	 */
dvander@105
   274
dvander@105
   275
	/* Part 1: Check if we're in the memory bounds */
dvander@105
   276
	//cmp <reg>, [esi+info.stpu]
dvander@105
   277
	//jae :error
dvander@105
   278
	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_STACKTOP_U);
dvander@105
   279
	IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
dvander@105
   280
dvander@105
   281
	/* Part 2: Check if we're in the invalid region between HP and SP */
dvander@105
   282
	jitoffs_t jmp;
dvander@105
   283
	//cmp <reg>, [esi+info.heap]
dvander@105
   284
	//jb :continue
dvander@105
   285
	//lea ecx, [ebp+<reg>]
dvander@105
   286
	//cmp edi, ecx
dvander@105
   287
	//jb :error
dvander@105
   288
	//:continue
dvander@75
   289
	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   290
	jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
dvander@105
   291
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
dvander@105
   292
	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
dvander@105
   293
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
dvander@105
   294
	IA32_Send_Jump8_Here(jit, jmp);
dvander@105
   295
dvander@75
   296
	if (call)
dvander@75
   297
	{
dvander@75
   298
		IA32_Return(jit);
dvander@75
   299
	}
dvander@75
   300
}
dvander@75
   301
dvander@70
   302
void Macro_PushN_Addr(JitWriter *jit, int i)
dvander@70
   303
{
dvander@70
   304
	//push eax
faluco@97
   305
	//mov eax, [esi+frm]
dvander@70
   306
	//loop i times:
dvander@70
   307
	// lea ecx, [eax+<val>]
faluco@97
   308
	// mov [edi-4*i], ecx
faluco@97
   309
	//sub edi, 4*N
dvander@70
   310
	//pop eax
dvander@70
   311
dvander@70
   312
	cell_t val;
dvander@70
   313
	int n = 1;
dvander@70
   314
	IA32_Push_Reg(jit, AMX_REG_PRI);
faluco@97
   315
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
dvander@70
   316
	do
dvander@70
   317
	{
dvander@70
   318
		val = jit->read_cell();
dvander@70
   319
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   320
			IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
dvander@70
   321
		else
dvander@70
   322
			IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
dvander@70
   323
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   324
	} while (n++ < i);
dvander@70
   325
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   326
	IA32_Pop_Reg(jit, AMX_REG_PRI);
dvander@70
   327
}
dvander@70
   328
dvander@70
   329
void Macro_PushN_S(JitWriter *jit, int i)
dvander@70
   330
{
dvander@70
   331
	//loop i times:
dvander@70
   332
	// mov ecx, [ebx+<val>]
faluco@97
   333
	// mov [edi-4*i], ecx
faluco@97
   334
	//sub edi, 4*N
dvander@70
   335
dvander@70
   336
	cell_t val;
dvander@70
   337
	int n = 1;
dvander@70
   338
	do 
dvander@70
   339
	{
dvander@70
   340
		val = jit->read_cell();
dvander@70
   341
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   342
			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
dvander@70
   343
		else
dvander@70
   344
			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
dvander@70
   345
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   346
	} while (n++ < i);
dvander@70
   347
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   348
}
dvander@70
   349
dvander@70
   350
void Macro_PushN_C(JitWriter *jit, int i)
dvander@70
   351
{
dvander@70
   352
	//loop i times:
faluco@97
   353
	// mov [edi-4*i], <val>
faluco@97
   354
	//sub edi, 4*N
dvander@70
   355
dvander@70
   356
	int n = 1;
dvander@70
   357
	do 
dvander@70
   358
	{
dvander@70
   359
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
dvander@70
   360
	} while (n++ < i);
dvander@70
   361
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   362
}
dvander@70
   363
dvander@70
   364
void Macro_PushN(JitWriter *jit, int i)
dvander@70
   365
{
dvander@70
   366
	//loop i times:
faluco@97
   367
	// mov ecx, [ebp+<val>]
faluco@97
   368
	// mov [edi-4*i], ecx
faluco@97
   369
	//sub edi, 4*N
dvander@70
   370
dvander@70
   371
	cell_t val;
dvander@70
   372
	int n = 1;
dvander@70
   373
	do 
dvander@70
   374
	{
dvander@70
   375
		val = jit->read_cell();
dvander@70
   376
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   377
			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
dvander@70
   378
		else
dvander@70
   379
			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
dvander@70
   380
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   381
	} while (n++ < i);
dvander@70
   382
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   383
}
dvander@70
   384
dvander@105
   385
void WriteOp_Sysreq_N_Function(JitWriter *jit)
dvander@105
   386
{
dvander@105
   387
	/* The big daddy of opcodes.
dvander@105
   388
	 * eax - num_params
dvander@105
   389
	 * ecx - native index
dvander@105
   390
	 */
dvander@105
   391
	CompData *data = (CompData *)jit->data;
dvander@105
   392
dvander@105
   393
	/* store the number of parameters on the stack */
dvander@105
   394
	//mov [edi-4], eax
dvander@105
   395
	//sub edi, 4
dvander@105
   396
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
dvander@105
   397
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
dvander@105
   398
dvander@105
   399
	/* save registers we will need */
dvander@105
   400
	//push eax	; num_params for stack popping
dvander@105
   401
	//push edx
dvander@105
   402
	IA32_Push_Reg(jit, REG_EAX);
dvander@105
   403
	IA32_Push_Reg(jit, AMX_REG_ALT);
dvander@105
   404
dvander@105
   405
	/* push some callback stuff */
dvander@105
   406
	//push edi		; stack
dvander@105
   407
	//push ecx		; native index
dvander@105
   408
	IA32_Push_Reg(jit, AMX_REG_STK);
dvander@105
   409
	IA32_Push_Reg(jit, REG_ECX);
dvander@105
   410
dvander@105
   411
	/* Relocate stack, heap, frm information, then store back */
dvander@105
   412
	//sub edi, ebp
dvander@105
   413
	//mov ecx, [esi+hea]
dvander@105
   414
	//mov eax, [esi+context]
dvander@105
   415
	//mov [eax+hp], ecx
dvander@105
   416
	//mov [eax+sp], edi
dvander@105
   417
	//mov ecx, [esi+frm]
dvander@105
   418
	//mov [eax+frm], ecx
dvander@105
   419
	IA32_Sub_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@105
   420
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   421
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
dvander@105
   422
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
dvander@105
   423
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
dvander@105
   424
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_REG);
dvander@105
   425
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
dvander@105
   426
dvander@105
   427
	/* finally, push the last parameter and make the call */
dvander@105
   428
	//push eax		; context
dvander@105
   429
	//mov eax, [eax+context]
dvander@105
   430
	//call NativeCallback
dvander@105
   431
	IA32_Push_Reg(jit, REG_EAX);
dvander@105
   432
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@105
   433
	IA32_Write_Jump32(jit, call, (jitoffs_t)(char *)&NativeCallback);
dvander@105
   434
dvander@105
   435
	/* restore what we damaged */
dvander@105
   436
	//add esp, 4*3
dvander@105
   437
	//add edi, ebp
dvander@105
   438
	//pop edx
dvander@105
   439
	//pop ecx	; num_params
dvander@105
   440
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
dvander@105
   441
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@105
   442
	IA32_Pop_Reg(jit, AMX_REG_ALT);
dvander@105
   443
	IA32_Pop_Reg(jit, REG_ECX);
dvander@105
   444
dvander@105
   445
	//Note: always safe, we're in a call
dvander@105
   446
	//test eax, eax
dvander@105
   447
	//jne :error
dvander@105
   448
	IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
dvander@105
   449
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NE, data->jit_return);
dvander@105
   450
dvander@105
   451
	/* pop the AMX stack.  do not check the margins.
dvander@105
   452
	 * Note that this is not a true macro - we don't bother to
dvander@105
   453
	 * set ALT here because nothing will be using it.
dvander@105
   454
	 */
dvander@105
   455
	//lea edi, [edi+ecx*4+4]
dvander@105
   456
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
dvander@105
   457
dvander@105
   458
	//ret
dvander@105
   459
	IA32_Return(jit);
dvander@105
   460
}
dvander@105
   461
dvander@70
   462
JITX86::JITX86()
dvander@70
   463
{
dvander@70
   464
	memset(OpAdvTable, -1, sizeof(OpAdvTable));
dvander@70
   465
dvander@70
   466
	/* instructions with 5 parameters */
dvander@70
   467
	OpAdvTable[OP_PUSH5_C] = sizeof(cell_t)*5;
dvander@70
   468
	OpAdvTable[OP_PUSH5] = sizeof(cell_t)*5;
dvander@70
   469
	OpAdvTable[OP_PUSH5_S] = sizeof(cell_t)*5;
dvander@70
   470
	OpAdvTable[OP_PUSH5_ADR] = sizeof(cell_t)*5;
dvander@70
   471
dvander@70
   472
	/* instructions with 4 parameters */
dvander@70
   473
	OpAdvTable[OP_PUSH4_C] = sizeof(cell_t)*4;
dvander@70
   474
	OpAdvTable[OP_PUSH4] = sizeof(cell_t)*4;
dvander@70
   475
	OpAdvTable[OP_PUSH4_S] = sizeof(cell_t)*4;
dvander@70
   476
	OpAdvTable[OP_PUSH4_ADR] = sizeof(cell_t)*4;
dvander@70
   477
dvander@70
   478
	/* instructions with 3 parameters */
dvander@70
   479
	OpAdvTable[OP_PUSH3_C] = sizeof(cell_t)*3;
dvander@70
   480
	OpAdvTable[OP_PUSH3] = sizeof(cell_t)*3;
dvander@70
   481
	OpAdvTable[OP_PUSH3_S] = sizeof(cell_t)*3;
dvander@70
   482
	OpAdvTable[OP_PUSH3_ADR] = sizeof(cell_t)*3;
dvander@70
   483
dvander@70
   484
	/* instructions with 2 parameters */
dvander@70
   485
	OpAdvTable[OP_PUSH2_C] = sizeof(cell_t)*2;
dvander@70
   486
	OpAdvTable[OP_PUSH2] = sizeof(cell_t)*2;
dvander@70
   487
	OpAdvTable[OP_PUSH2_S] = sizeof(cell_t)*2;
dvander@70
   488
	OpAdvTable[OP_PUSH2_ADR] = sizeof(cell_t)*2;
dvander@70
   489
	OpAdvTable[OP_LOAD_BOTH] = sizeof(cell_t)*2;
dvander@70
   490
	OpAdvTable[OP_LOAD_S_BOTH] = sizeof(cell_t)*2;
dvander@70
   491
	OpAdvTable[OP_CONST] = sizeof(cell_t)*2;
dvander@70
   492
	OpAdvTable[OP_CONST_S] = sizeof(cell_t)*2;
dvander@74
   493
	OpAdvTable[OP_SYSREQ_N] = sizeof(cell_t)*2;
dvander@70
   494
dvander@70
   495
	/* instructions with 1 parameter */
dvander@70
   496
	OpAdvTable[OP_LOAD_PRI] = sizeof(cell_t);
dvander@70
   497
	OpAdvTable[OP_LOAD_ALT] = sizeof(cell_t);
dvander@70
   498
	OpAdvTable[OP_LOAD_S_PRI] = sizeof(cell_t);
dvander@70
   499
	OpAdvTable[OP_LOAD_S_ALT] = sizeof(cell_t);
dvander@70
   500
	OpAdvTable[OP_LREF_PRI] = sizeof(cell_t);
dvander@70
   501
	OpAdvTable[OP_LREF_ALT] = sizeof(cell_t);
dvander@70
   502
	OpAdvTable[OP_LREF_S_PRI] = sizeof(cell_t);
dvander@70
   503
	OpAdvTable[OP_LREF_S_ALT] = sizeof(cell_t);
dvander@70
   504
	OpAdvTable[OP_CONST_PRI] = sizeof(cell_t);
dvander@70
   505
	OpAdvTable[OP_CONST_ALT] = sizeof(cell_t);
dvander@70
   506
	OpAdvTable[OP_ADDR_PRI] = sizeof(cell_t);
dvander@70
   507
	OpAdvTable[OP_ADDR_ALT] = sizeof(cell_t);
dvander@70
   508
	OpAdvTable[OP_STOR_PRI] = sizeof(cell_t);
dvander@70
   509
	OpAdvTable[OP_STOR_ALT] = sizeof(cell_t);
dvander@70
   510
	OpAdvTable[OP_STOR_S_PRI] = sizeof(cell_t);
dvander@70
   511
	OpAdvTable[OP_STOR_S_ALT] = sizeof(cell_t);
dvander@70
   512
	OpAdvTable[OP_SREF_PRI] = sizeof(cell_t);
dvander@70
   513
	OpAdvTable[OP_SREF_ALT] = sizeof(cell_t);
dvander@70
   514
	OpAdvTable[OP_SREF_S_PRI] = sizeof(cell_t);
dvander@70
   515
	OpAdvTable[OP_SREF_S_ALT] = sizeof(cell_t);
dvander@70
   516
	OpAdvTable[OP_LIDX_B] = sizeof(cell_t);
dvander@70
   517
	OpAdvTable[OP_IDXADDR_B] = sizeof(cell_t);
dvander@70
   518
	OpAdvTable[OP_PUSH_C] = sizeof(cell_t);
dvander@70
   519
	OpAdvTable[OP_PUSH] = sizeof(cell_t);
dvander@70
   520
	OpAdvTable[OP_PUSH_S] = sizeof(cell_t);
dvander@70
   521
	OpAdvTable[OP_STACK] = sizeof(cell_t);
dvander@70
   522
	OpAdvTable[OP_HEAP] = sizeof(cell_t);
dvander@70
   523
	OpAdvTable[OP_SHL_C_PRI] = sizeof(cell_t);
dvander@70
   524
	OpAdvTable[OP_SHL_C_ALT] = sizeof(cell_t);
dvander@70
   525
	OpAdvTable[OP_SHR_C_PRI] = sizeof(cell_t);
dvander@70
   526
	OpAdvTable[OP_SHR_C_ALT] = sizeof(cell_t);
dvander@70
   527
	OpAdvTable[OP_ADD_C] = sizeof(cell_t);
dvander@70
   528
	OpAdvTable[OP_SMUL_C] = sizeof(cell_t);
dvander@70
   529
	OpAdvTable[OP_ZERO] = sizeof(cell_t);
dvander@70
   530
	OpAdvTable[OP_ZERO_S] = sizeof(cell_t);
dvander@70
   531
	OpAdvTable[OP_EQ_C_PRI] = sizeof(cell_t);
dvander@70
   532
	OpAdvTable[OP_EQ_C_ALT] = sizeof(cell_t);
dvander@70
   533
	OpAdvTable[OP_INC] = sizeof(cell_t);
dvander@70
   534
	OpAdvTable[OP_INC_S] = sizeof(cell_t);
dvander@70
   535
	OpAdvTable[OP_DEC] = sizeof(cell_t);
dvander@70
   536
	OpAdvTable[OP_DEC_S] = sizeof(cell_t);
dvander@70
   537
	OpAdvTable[OP_MOVS] = sizeof(cell_t);
dvander@70
   538
	OpAdvTable[OP_FILL] = sizeof(cell_t);
dvander@70
   539
	OpAdvTable[OP_HALT] = sizeof(cell_t);
dvander@70
   540
	OpAdvTable[OP_BOUNDS] = sizeof(cell_t);
dvander@70
   541
	OpAdvTable[OP_PUSH_ADR] = sizeof(cell_t);
dvander@71
   542
	OpAdvTable[OP_PUSH_HEAP_C] = sizeof(cell_t);
dvander@74
   543
	OpAdvTable[OP_SYSREQ_C] = sizeof(cell_t);
dvander@98
   544
	OpAdvTable[OP_CALL] = sizeof(cell_t);
dvander@98
   545
	OpAdvTable[OP_JUMP] = sizeof(cell_t);
dvander@98
   546
	OpAdvTable[OP_JZER] = sizeof(cell_t);
dvander@98
   547
	OpAdvTable[OP_JNZ] = sizeof(cell_t);
dvander@98
   548
	OpAdvTable[OP_JEQ] = sizeof(cell_t);
dvander@98
   549
	OpAdvTable[OP_JNEQ] = sizeof(cell_t);
dvander@98
   550
	OpAdvTable[OP_JSLESS] = sizeof(cell_t);
dvander@98
   551
	OpAdvTable[OP_JSLEQ] = sizeof(cell_t);
dvander@98
   552
	OpAdvTable[OP_JSGRTR] = sizeof(cell_t);
dvander@98
   553
	OpAdvTable[OP_JSGEQ] = sizeof(cell_t);
dvander@98
   554
	OpAdvTable[OP_SWITCH] = sizeof(cell_t);
dvander@70
   555
dvander@70
   556
	/* instructions with 0 parameters */
dvander@70
   557
	OpAdvTable[OP_LOAD_I] = 0;
dvander@70
   558
	OpAdvTable[OP_STOR_I] = 0;
dvander@70
   559
	OpAdvTable[OP_LIDX] = 0;
dvander@70
   560
	OpAdvTable[OP_IDXADDR] = 0;
dvander@70
   561
	OpAdvTable[OP_MOVE_PRI] = 0;
dvander@70
   562
	OpAdvTable[OP_MOVE_ALT] = 0;
dvander@70
   563
	OpAdvTable[OP_XCHG] = 0;
dvander@70
   564
	OpAdvTable[OP_PUSH_PRI] = 0;
dvander@70
   565
	OpAdvTable[OP_PUSH_ALT] = 0;
dvander@70
   566
	OpAdvTable[OP_POP_PRI] = 0;
dvander@70
   567
	OpAdvTable[OP_POP_ALT] = 0;
dvander@70
   568
	OpAdvTable[OP_PROC] = 0;
dvander@70
   569
	OpAdvTable[OP_RET] = 0;
dvander@70
   570
	OpAdvTable[OP_RETN] = 0;
dvander@70
   571
	OpAdvTable[OP_CALL_PRI] = 0;
dvander@70
   572
	OpAdvTable[OP_SHL] = 0;
dvander@70
   573
	OpAdvTable[OP_SHR] = 0;
dvander@70
   574
	OpAdvTable[OP_SSHR] = 0;
dvander@70
   575
	OpAdvTable[OP_SMUL] = 0;
dvander@70
   576
	OpAdvTable[OP_SDIV] = 0;
dvander@70
   577
	OpAdvTable[OP_SDIV_ALT] = 0;
dvander@70
   578
	OpAdvTable[OP_ADD] = 0;
dvander@70
   579
	OpAdvTable[OP_SUB] = 0;
dvander@70
   580
	OpAdvTable[OP_SUB_ALT] = 0;
dvander@70
   581
	OpAdvTable[OP_AND] = 0;
dvander@70
   582
	OpAdvTable[OP_OR] = 0;
dvander@70
   583
	OpAdvTable[OP_XOR] = 0;
dvander@70
   584
	OpAdvTable[OP_NOT] = 0;
dvander@70
   585
	OpAdvTable[OP_NEG] = 0;
dvander@70
   586
	OpAdvTable[OP_INVERT] = 0;
dvander@70
   587
	OpAdvTable[OP_ZERO_PRI] = 0;
dvander@70
   588
	OpAdvTable[OP_ZERO_ALT] = 0;
dvander@70
   589
	OpAdvTable[OP_SIGN_PRI] = 0;
dvander@70
   590
	OpAdvTable[OP_SIGN_ALT] = 0;
dvander@70
   591
	OpAdvTable[OP_EQ] = 0;
dvander@70
   592
	OpAdvTable[OP_NEQ] = 0;
dvander@70
   593
	OpAdvTable[OP_SLESS] = 0;
dvander@70
   594
	OpAdvTable[OP_SLEQ] = 0;
dvander@70
   595
	OpAdvTable[OP_SGRTR] = 0;
dvander@70
   596
	OpAdvTable[OP_SGEQ] = 0;
dvander@70
   597
	OpAdvTable[OP_INC_PRI] = 0;
dvander@70
   598
	OpAdvTable[OP_INC_ALT] = 0;
dvander@70
   599
	OpAdvTable[OP_INC_I] = 0;
dvander@70
   600
	OpAdvTable[OP_DEC_PRI] = 0;
dvander@70
   601
	OpAdvTable[OP_DEC_ALT] = 0;
dvander@70
   602
	OpAdvTable[OP_DEC_I] = 0;
dvander@70
   603
	OpAdvTable[OP_JUMP_PRI] = 0;
dvander@70
   604
	OpAdvTable[OP_SWAP_PRI] = 0;
dvander@70
   605
	OpAdvTable[OP_SWAP_ALT] = 0;
dvander@70
   606
	OpAdvTable[OP_NOP] = 0;
dvander@70
   607
	OpAdvTable[OP_BREAK] = 0;
dvander@71
   608
	OpAdvTable[OP_HEAP_PRI] = 0;
dvander@71
   609
	OpAdvTable[OP_POP_HEAP_PRI] = 0;
dvander@74
   610
	OpAdvTable[OP_SYSREQ_PRI] = 0;
dvander@70
   611
dvander@70
   612
	/* opcodes that are totally invalid */
dvander@93
   613
	/* :TODO: make an alternate table if USE_UNGEN_OPCODES is on? */
dvander@70
   614
	OpAdvTable[OP_FILE] = -3;
dvander@70
   615
	OpAdvTable[OP_SYMBOL] = -3;
dvander@70
   616
	OpAdvTable[OP_LINE] = -3;
dvander@70
   617
	OpAdvTable[OP_SRANGE] = -3;
dvander@70
   618
	OpAdvTable[OP_SYMTAG] = -3;
dvander@70
   619
	OpAdvTable[OP_SYSREQ_D] = -3;
dvander@70
   620
	OpAdvTable[OP_SYSREQ_ND] = -3;
dvander@70
   621
	OpAdvTable[OP_PUSH_R] = -3;
dvander@93
   622
	OpAdvTable[OP_LODB_I] = -3;
dvander@93
   623
	OpAdvTable[OP_STRB_I] = -3;
dvander@93
   624
	OpAdvTable[OP_LCTRL] = -3;
dvander@93
   625
	OpAdvTable[OP_SCTRL] = -3;
dvander@93
   626
	OpAdvTable[OP_ALIGN_PRI] = -3;
dvander@93
   627
	OpAdvTable[OP_ALIGN_ALT] = -3;
dvander@93
   628
	OpAdvTable[OP_JREL] = -3;
dvander@93
   629
	OpAdvTable[OP_CMPS] = -3;
dvander@93
   630
	OpAdvTable[OP_UMUL] = -3;
dvander@93
   631
	OpAdvTable[OP_UDIV] = -3;
dvander@93
   632
	OpAdvTable[OP_UDIV_ALT] = -3;
dvander@93
   633
	OpAdvTable[OP_LESS] = -3;
dvander@93
   634
	OpAdvTable[OP_LEQ] = -3;
dvander@93
   635
	OpAdvTable[OP_GRTR] = -3;
dvander@93
   636
	OpAdvTable[OP_GEQ] = -3;
dvander@93
   637
	OpAdvTable[OP_JLESS] = -3;
dvander@93
   638
	OpAdvTable[OP_JLEQ] = -3;
dvander@93
   639
	OpAdvTable[OP_JGRTR] = -3;
dvander@93
   640
	OpAdvTable[OP_JGEQ] = -3;
dvander@70
   641
}