sourcepawn/vm/jit/x86/opcode_helpers.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sat Nov 04 18:30:20 2006 +0000 (2006-11-04)
changeset 134 eded7cf8e114
parent 131 6958fb3f3c3d
child 135 8c40a68f4286
permissions -rw-r--r--
added tracker push helper
dyn arrays are working now
dvander@70
     1
#include <limits.h>
dvander@70
     2
#include <string.h>
faluco@130
     3
#include <malloc.h>
dvander@70
     4
#include "jit_x86.h"
dvander@70
     5
#include "opcode_helpers.h"
dvander@70
     6
#include "x86_macros.h"
dvander@70
     7
faluco@125
     8
#define NUM_INFO_PARAMS	5
dvander@105
     9
dvander@93
    10
jitoffs_t Write_Execute_Function(JitWriter *jit)
dvander@73
    11
{
dvander@73
    12
	/** 
dvander@73
    13
	 * The variables we're passed in:
dvander@73
    14
	 *  sp_context_t *ctx, uint32_t code_idx, cell_t *result
dvander@73
    15
	 */
dvander@73
    16
dvander@74
    17
	/**
dvander@74
    18
	 * !NOTE!
dvander@74
    19
	 * Currently, we do not accept ctx->frm as the new frame pointer.
dvander@74
    20
	 * Instead, we copy the frame from the stack pointer.
dvander@74
    21
	 * This is because we do not support resuming or sleeping!
dvander@74
    22
	 */
dvander@73
    23
dvander@74
    24
	//push ebp
dvander@74
    25
	//mov ebp, esp
dvander@74
    26
	IA32_Push_Reg(jit, REG_EBP);
dvander@74
    27
	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
dvander@74
    28
dvander@74
    29
	//push esi
dvander@74
    30
	//push edi
dvander@74
    31
	//push ebx
dvander@74
    32
	IA32_Push_Reg(jit, REG_ESI);
dvander@74
    33
	IA32_Push_Reg(jit, REG_EDI);
dvander@74
    34
	IA32_Push_Reg(jit, REG_EBX);
dvander@74
    35
dvander@105
    36
	//sub esp, 4*n	- reserve info array
dvander@74
    37
	//mov esi, esp	- save info pointer
dvander@105
    38
	IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
dvander@74
    39
	IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
dvander@74
    40
dvander@83
    41
	/* Initial memory setup */
dvander@83
    42
	//mov eax, [ebp+16]		- get result pointer
dvander@83
    43
	//mov [esi+8], eax		- store into info pointer
dvander@74
    44
	//mov eax, [ebp+8]		- get context
dvander@74
    45
	//mov [esi+12], eax		- store context into info pointer
dvander@74
    46
	//mov ecx, [eax+<offs>]	- get heap pointer
dvander@74
    47
	//mov [esi+4], ecx		- store heap into info pointer
dvander@105
    48
	//mov ebp, [eax+<offs>]	- get data pointer
dvander@83
    49
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
dvander@83
    50
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
dvander@74
    51
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
dvander@83
    52
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
dvander@74
    53
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
dvander@83
    54
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
dvander@74
    55
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, data));
dvander@74
    56
dvander@83
    57
	/* Frame setup */
dvander@105
    58
	//mov edi, [eax+<offs>]	- get stack pointer
dvander@105
    59
	//add edi, ebp			- relocate to data section
dvander@105
    60
	//mov ebx, edi			- copy sp to frm
dvander@75
    61
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
dvander@105
    62
	IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@75
    63
	IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
dvander@75
    64
dvander@83
    65
	/* Info memory setup */
dvander@105
    66
	//mov ecx, [eax+<offs>] - copy memsize to temp var
dvander@105
    67
	//add ecx, ebp			- relocate
dvander@105
    68
	//mov [esi+x], ecx		- store relocated
dvander@105
    69
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, memory));
dvander@105
    70
	IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
dvander@83
    71
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
dvander@75
    72
dvander@83
    73
	/* Remaining needed vars */
dvander@105
    74
	//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
    75
	//add ecx, [eax+<offs>]   - add code base to index
dvander@105
    76
	IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
dvander@93
    77
	IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
dvander@74
    78
dvander@74
    79
	/* by now, everything is set up, so we can call into the plugin */
dvander@74
    80
	//call ecx
dvander@86
    81
	IA32_Call_Reg(jit, REG_ECX);
dvander@74
    82
dvander@74
    83
	/* if the code flow gets to here, there was a normal return */
dvander@105
    84
	//mov ecx, [esi+8]		- get retval pointer
dvander@105
    85
	//mov [ecx], eax		- store retval from PRI
dvander@113
    86
	//mov eax, SP_ERROR_NONE	- set no error
dvander@105
    87
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
dvander@105
    88
	IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
dvander@113
    89
	IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
dvander@74
    90
dvander@75
    91
	/* save where error checking/halting functions should go to */
dvander@105
    92
	jitoffs_t offs_return = jit->get_outputpos();
dvander@105
    93
	//mov esp, esi			- restore stack pointer
dvander@105
    94
	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
dvander@74
    95
dvander@105
    96
	/* _FOR NOW_ ...
dvander@105
    97
	 * We are going to restore SP, HP, and FRM for now.  This is for 
dvander@105
    98
     * debugging only, to check for alignment errors.  As such:
dvander@105
    99
	 * :TODO: probably remove this.
dvander@74
   100
	 */
dvander@105
   101
	//mov ecx, [esi+context]
dvander@105
   102
	//sub edi, ebp
dvander@105
   103
	//mov edx, [esi+heap]
dvander@105
   104
	//mov [ecx+sp], edi
dvander@105
   105
	//mov [ecx+hp], edx
dvander@105
   106
	IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
dvander@105
   107
	IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
dvander@105
   108
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
dvander@105
   109
	IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
faluco@134
   110
	IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
dvander@74
   111
dvander@105
   112
	//add esp, 4*NUM_INFO_PARAMS
dvander@74
   113
	//pop ebx
dvander@74
   114
	//pop edi
dvander@74
   115
	//pop esi
dvander@74
   116
	//pop ebp
dvander@74
   117
	//ret
dvander@105
   118
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
dvander@74
   119
	IA32_Pop_Reg(jit, REG_EBX);
dvander@74
   120
	IA32_Pop_Reg(jit, REG_EDI);
dvander@74
   121
	IA32_Pop_Reg(jit, REG_ESI);
dvander@74
   122
	IA32_Pop_Reg(jit, REG_EBP);
dvander@74
   123
	IA32_Return(jit);
dvander@74
   124
dvander@74
   125
	return offs_return;
dvander@73
   126
}
dvander@73
   127
dvander@86
   128
void Write_BreakDebug(JitWriter *jit)
dvander@86
   129
{
dvander@86
   130
	//push ecx
dvander@86
   131
	//mov ecx, [esi+ctx]
dvander@86
   132
	//cmp [ecx+dbreak], 0
dvander@86
   133
	//jnz :nocall
dvander@86
   134
	IA32_Push_Reg(jit, AMX_REG_TMP);
dvander@86
   135
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
faluco@97
   136
	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
dvander@86
   137
	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
dvander@86
   138
dvander@86
   139
	//pushad
dvander@86
   140
	IA32_Pushad(jit);
dvander@86
   141
dvander@86
   142
	//push [esi+frm]
dvander@86
   143
	//push [ecx+context]
dvander@86
   144
	//mov ecx, [ecx+dbreak]
dvander@86
   145
	//call ecx
dvander@86
   146
	//add esp, 8
dvander@86
   147
	//popad
faluco@97
   148
	IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
dvander@86
   149
	IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, context));
dvander@86
   150
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
dvander@86
   151
	IA32_Call_Reg(jit, AMX_REG_TMP);
dvander@86
   152
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
dvander@86
   153
	IA32_Popad(jit);
dvander@86
   154
dvander@86
   155
	//:nocall
dvander@86
   156
	IA32_Send_Jump8_Here(jit, jmp);
dvander@86
   157
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*1, MOD_REG);
dvander@86
   158
	IA32_Return(jit);
dvander@86
   159
}
dvander@86
   160
dvander@112
   161
void Write_GetError(JitWriter *jit)
dvander@75
   162
{
dvander@75
   163
	CompData *data = (CompData *)jit->data;
dvander@75
   164
dvander@112
   165
	//mov eax, [esi+info.context]
dvander@112
   166
	//mov eax, [eax+ctx.error]
dvander@112
   167
	//jmp [jit_return]
dvander@112
   168
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
dvander@112
   169
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, err));
dvander@112
   170
	IA32_Jump_Imm32_Abs(jit, data->jit_return);
dvander@112
   171
}
dvander@112
   172
dvander@112
   173
void Write_SetError(JitWriter *jit, int error)
dvander@112
   174
{
dvander@112
   175
	CompData *data = (CompData *)jit->data;
dvander@112
   176
dvander@75
   177
	//mov eax, <error>
dvander@112
   178
	//jmp [jit_return]
dvander@75
   179
	IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
dvander@112
   180
	IA32_Jump_Imm32_Abs(jit, data->jit_return);
dvander@75
   181
}
dvander@75
   182
faluco@81
   183
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
faluco@81
   184
{
faluco@81
   185
	//test reg, reg
dvander@105
   186
	//jz :error
faluco@81
   187
	IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
dvander@105
   188
	IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
dvander@105
   189
}
dvander@105
   190
dvander@105
   191
void Write_CheckHeap_Min(JitWriter *jit)
dvander@105
   192
{
dvander@105
   193
	/* Check if the stack went beyond the heap low.
dvander@105
   194
	 * This usually means there was a compiler error.
dvander@105
   195
	 * NOTE: Special optimization here.
dvander@105
   196
	 * The heap low is always known ahead of time! :)
dvander@105
   197
	 */
dvander@105
   198
	CompData *data = (CompData *)jit->data;
dvander@105
   199
	//cmp [esi+info.heap], <heaplow>
dvander@105
   200
	//jb :error
dvander@105
   201
	IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
dvander@105
   202
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
dvander@105
   203
}
faluco@81
   204
dvander@105
   205
void Write_CheckHeap_Low(JitWriter *jit)
dvander@105
   206
{
dvander@105
   207
	/* Check if the heap is trying to grow beyond the stack.
dvander@105
   208
	 */
dvander@105
   209
	//mov ecx, [esi+info.heap]
dvander@105
   210
	//lea ecx, [ebp+ecx+STACK_MARGIN]
dvander@105
   211
	//cmp ecx, edi
dvander@105
   212
	//ja :error		; I think this is right
dvander@105
   213
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   214
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
dvander@105
   215
	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
dvander@105
   216
	IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
faluco@81
   217
}
dvander@105
   218
dvander@105
   219
void Write_CheckStack_Min(JitWriter *jit)
dvander@105
   220
{
dvander@105
   221
	/* Check if the stack went beyond the stack top
dvander@105
   222
	 * This usually means there was a compiler error.
dvander@105
   223
	 */
dvander@105
   224
	//cmp edi, [esi+info.stacktop]
dvander@105
   225
	//jae :error
dvander@105
   226
	IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
dvander@105
   227
	IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
dvander@105
   228
}
dvander@105
   229
dvander@105
   230
void Write_CheckStack_Low(JitWriter *jit)
dvander@105
   231
{
dvander@105
   232
	/* Check if the stack went beyond the heap boundary.
dvander@105
   233
	 * Unfortunately this one isn't as quick as the other check.
dvander@105
   234
	 * The stack margin check is important for sysreq.n having space.
dvander@105
   235
	 */
dvander@105
   236
	//mov ecx, [esi+info.heap]
dvander@105
   237
	//lea ecx, [ebp+ecx+STACK_MARGIN]
dvander@105
   238
	//cmp edi, ecx
dvander@105
   239
	//jb :error		; I think this is right
dvander@105
   240
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   241
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
dvander@105
   242
	IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
dvander@105
   243
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
dvander@105
   244
}
dvander@105
   245
dvander@105
   246
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
dvander@75
   247
{
dvander@75
   248
	CompData *data = (CompData *)jit->data;
dvander@75
   249
dvander@75
   250
	/* :TODO: Should this be checking for below heaplow?
dvander@75
   251
	 * The old JIT did not.
dvander@75
   252
	 */
dvander@75
   253
dvander@75
   254
	bool call = false;
dvander@75
   255
	if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
dvander@75
   256
	{
dvander@75
   257
		/* If we're not in the initial generation phase,
dvander@75
   258
		 * Write a call to the actual routine instead.
dvander@75
   259
		 */
dvander@105
   260
		if ((reg == REG_EAX) && data->jit_verify_addr_eax)
dvander@75
   261
		{
dvander@75
   262
			jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@105
   263
			IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
dvander@105
   264
			return;
dvander@105
   265
		} else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
dvander@105
   266
			jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@105
   267
			IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
dvander@75
   268
			return;
dvander@75
   269
		}
dvander@75
   270
		call = true;
dvander@75
   271
	}
dvander@75
   272
dvander@105
   273
	/** 
dvander@105
   274
	 * :TODO: If we can't find a nicer way of doing this,
dvander@105
   275
	 *  then scrap it on high optimizations.  The second portion is not needed at all!
dvander@105
   276
	 */
dvander@105
   277
dvander@105
   278
	/* Part 1: Check if we're in the memory bounds */
faluco@125
   279
	//cmp <reg>, <stpu>
dvander@105
   280
	//jae :error
faluco@125
   281
	IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
dvander@105
   282
	IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
dvander@105
   283
dvander@105
   284
	/* Part 2: Check if we're in the invalid region between HP and SP */
dvander@105
   285
	jitoffs_t jmp;
dvander@105
   286
	//cmp <reg>, [esi+info.heap]
dvander@105
   287
	//jb :continue
dvander@105
   288
	//lea ecx, [ebp+<reg>]
dvander@105
   289
	//cmp edi, ecx
dvander@105
   290
	//jb :error
dvander@105
   291
	//:continue
dvander@75
   292
	IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@105
   293
	jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
dvander@105
   294
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
dvander@105
   295
	IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
dvander@105
   296
	IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
dvander@105
   297
	IA32_Send_Jump8_Here(jit, jmp);
dvander@105
   298
dvander@75
   299
	if (call)
dvander@75
   300
	{
dvander@75
   301
		IA32_Return(jit);
dvander@75
   302
	}
dvander@75
   303
}
dvander@75
   304
dvander@70
   305
void Macro_PushN_Addr(JitWriter *jit, int i)
dvander@70
   306
{
dvander@70
   307
	//push eax
faluco@97
   308
	//mov eax, [esi+frm]
dvander@70
   309
	//loop i times:
dvander@70
   310
	// lea ecx, [eax+<val>]
faluco@97
   311
	// mov [edi-4*i], ecx
faluco@97
   312
	//sub edi, 4*N
dvander@70
   313
	//pop eax
dvander@70
   314
dvander@70
   315
	cell_t val;
dvander@70
   316
	int n = 1;
dvander@70
   317
	IA32_Push_Reg(jit, AMX_REG_PRI);
faluco@97
   318
	IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
dvander@70
   319
	do
dvander@70
   320
	{
dvander@70
   321
		val = jit->read_cell();
dvander@70
   322
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   323
			IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
dvander@70
   324
		else
dvander@70
   325
			IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
dvander@70
   326
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   327
	} while (n++ < i);
dvander@70
   328
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   329
	IA32_Pop_Reg(jit, AMX_REG_PRI);
dvander@70
   330
}
dvander@70
   331
dvander@70
   332
void Macro_PushN_S(JitWriter *jit, int i)
dvander@70
   333
{
dvander@70
   334
	//loop i times:
dvander@70
   335
	// mov ecx, [ebx+<val>]
faluco@97
   336
	// mov [edi-4*i], ecx
faluco@97
   337
	//sub edi, 4*N
dvander@70
   338
dvander@70
   339
	cell_t val;
dvander@70
   340
	int n = 1;
dvander@70
   341
	do 
dvander@70
   342
	{
dvander@70
   343
		val = jit->read_cell();
dvander@70
   344
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   345
			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
dvander@70
   346
		else
dvander@70
   347
			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
dvander@70
   348
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   349
	} while (n++ < i);
dvander@70
   350
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   351
}
dvander@70
   352
dvander@70
   353
void Macro_PushN_C(JitWriter *jit, int i)
dvander@70
   354
{
dvander@70
   355
	//loop i times:
faluco@97
   356
	// mov [edi-4*i], <val>
faluco@97
   357
	//sub edi, 4*N
dvander@70
   358
dvander@70
   359
	int n = 1;
dvander@70
   360
	do 
dvander@70
   361
	{
dvander@70
   362
		IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
dvander@70
   363
	} while (n++ < i);
dvander@70
   364
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   365
}
dvander@70
   366
dvander@70
   367
void Macro_PushN(JitWriter *jit, int i)
dvander@70
   368
{
dvander@70
   369
	//loop i times:
faluco@97
   370
	// mov ecx, [ebp+<val>]
faluco@97
   371
	// mov [edi-4*i], ecx
faluco@97
   372
	//sub edi, 4*N
dvander@70
   373
dvander@70
   374
	cell_t val;
dvander@70
   375
	int n = 1;
dvander@70
   376
	do 
dvander@70
   377
	{
dvander@70
   378
		val = jit->read_cell();
dvander@70
   379
		if (val < SCHAR_MAX && val > SCHAR_MIN)
dvander@70
   380
			IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
dvander@70
   381
		else
dvander@70
   382
			IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
dvander@70
   383
		IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
dvander@70
   384
	} while (n++ < i);
dvander@70
   385
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
dvander@70
   386
}
dvander@70
   387
dvander@113
   388
void WriteOp_Sysreq_C_Function(JitWriter *jit)
dvander@113
   389
{
dvander@113
   390
	/* The small daddy of the big daddy of opcodes.
dvander@113
   391
	 * ecx - native index
dvander@113
   392
	 */
dvander@113
   393
	CompData *data = (CompData *)jit->data;
dvander@113
   394
dvander@113
   395
	/* save registers we will need */
dvander@113
   396
	//push edx
dvander@113
   397
	IA32_Push_Reg(jit, AMX_REG_ALT);
dvander@113
   398
dvander@113
   399
	/* push some callback stuff */
dvander@113
   400
	//push edi		; stack
dvander@113
   401
	//push ecx		; native index
dvander@113
   402
	IA32_Push_Reg(jit, AMX_REG_STK);
dvander@113
   403
	IA32_Push_Reg(jit, REG_ECX);
dvander@113
   404
dvander@113
   405
	/* Relocate stack, heap, frm information, then store back */
faluco@125
   406
	//mov eax, [esi+context]
dvander@113
   407
	//mov ecx, [esi+hea]
faluco@125
   408
	//sub edi, ebp
dvander@113
   409
	//mov [eax+hp], ecx
faluco@125
   410
	//mov ecx, [esi]
dvander@113
   411
	//mov [eax+sp], edi
dvander@113
   412
	//mov [eax+frm], ecx
faluco@125
   413
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
dvander@113
   414
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
faluco@125
   415
	IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@113
   416
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
faluco@125
   417
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
dvander@113
   418
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
dvander@113
   419
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
dvander@113
   420
dvander@113
   421
	/* finally, push the last parameter and make the call */
dvander@113
   422
	//push eax		; context
dvander@113
   423
	//call NativeCallback
dvander@113
   424
	IA32_Push_Reg(jit, REG_EAX);
dvander@113
   425
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@113
   426
	if (!data->debug)
dvander@113
   427
	{
dvander@113
   428
		IA32_Write_Jump32_Abs(jit, call, NativeCallback);
dvander@113
   429
	} else {
dvander@113
   430
		IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug);
dvander@113
   431
	}
dvander@113
   432
dvander@113
   433
	/* Test for error */
dvander@113
   434
	//mov ecx, [esi+context]
dvander@113
   435
	//cmp [ecx+err], 0
dvander@113
   436
	//jnz :error
dvander@113
   437
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
faluco@125
   438
	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
dvander@113
   439
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
dvander@113
   440
dvander@113
   441
	/* restore what we damaged */
dvander@113
   442
	//add esp, 4*3
dvander@113
   443
	//add edi, ebp
dvander@113
   444
	//pop edx
dvander@113
   445
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
faluco@125
   446
	IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@113
   447
	IA32_Pop_Reg(jit, AMX_REG_ALT);
dvander@113
   448
dvander@113
   449
	//ret
dvander@113
   450
	IA32_Return(jit);
dvander@113
   451
}
dvander@113
   452
dvander@124
   453
void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], ucell_t _dimcount, bool autozero)
dvander@121
   454
{
dvander@121
   455
	cell_t vectors = 1;				/* we need one vector to start off with */
dvander@121
   456
	cell_t cur_offs = 0;
dvander@121
   457
	cell_t cur_write = 0;
dvander@124
   458
	cell_t dimcount = _dimcount;
dvander@121
   459
dvander@121
   460
	/* Initialize rotation */
dvander@121
   461
	cur_write = dims[dimcount-1];
dvander@121
   462
	
dvander@121
   463
	while (--dimcount >= 1)
dvander@121
   464
	{
dvander@121
   465
		cell_t cur_dim = dims[dimcount];
dvander@121
   466
		cell_t sub_dim = dims[dimcount-1];
dvander@121
   467
		for (cell_t i=0; i<vectors; i++)
dvander@121
   468
		{
dvander@121
   469
			for (cell_t j=0; j<cur_dim; j++)
dvander@121
   470
			{
dvander@121
   471
				arraybase[cur_offs] = (cur_write - cur_offs)*sizeof(cell_t);
dvander@121
   472
				cur_offs++;
dvander@121
   473
				cur_write += sub_dim;
dvander@121
   474
			}
dvander@121
   475
		}
dvander@121
   476
		vectors = cur_dim;
dvander@121
   477
	}
dvander@121
   478
dvander@124
   479
	/* everything after cur_offs can be zeroed */
dvander@124
   480
	if (autozero)
dvander@124
   481
	{
dvander@124
   482
		size_t size = 1;
dvander@124
   483
		for (ucell_t i=0; i<_dimcount; i++)
dvander@124
   484
		{
dvander@124
   485
			size *= dims[i];
dvander@124
   486
		}
dvander@124
   487
		memset(&arraybase[cur_offs], 0, size*sizeof(cell_t));
dvander@124
   488
	}
dvander@124
   489
dvander@121
   490
	return;
dvander@121
   491
}
dvander@121
   492
dvander@121
   493
/**
dvander@121
   494
 * A few notes about this function.
dvander@121
   495
 * I was more concerned about efficient use of registers here, rather than 
dvander@121
   496
 *  fine-tuned optimization.  The reason is that the code is already complicated,
dvander@121
   497
 *  and it is very easy to mess up.
dvander@121
   498
 */
dvander@120
   499
void WriteIntrinsic_GenArray(JitWriter *jit)
dvander@120
   500
{
dvander@121
   501
	/**
dvander@121
   502
	 * save important values
dvander@121
   503
	 */
dvander@121
   504
	//push ebx
dvander@121
   505
	//push eax
dvander@124
   506
	//push edx
dvander@121
   507
	//push ecx				;value is referenced on stack
dvander@121
   508
	IA32_Push_Reg(jit, REG_EBX);
dvander@121
   509
	IA32_Push_Reg(jit, REG_EAX);
dvander@124
   510
	IA32_Push_Reg(jit, REG_EDX);
dvander@121
   511
	IA32_Push_Reg(jit, REG_ECX);
dvander@121
   512
dvander@121
   513
	/**
dvander@121
   514
	 * Calculate how many cells will be needed.
dvander@121
   515
	 */
dvander@121
   516
	//mov edx, [edi]		;get last dimension's count
dvander@121
   517
	//mov eax, 1			;position at second to last dimension
dvander@121
   518
	//:loop
dvander@121
   519
	//cmp eax, [esp]		;compare to # of params
dvander@121
   520
	//jae :done				;end loop if done
dvander@121
   521
	//mov ecx, [edi+eax*4]	;get dimension size
dvander@121
   522
	//imul edx, ecx			;multiply by size
dvander@121
   523
	//add edx, ecx			;add size (indirection vector)
faluco@134
   524
	//add eax, 1			;increment
dvander@121
   525
	//jmp :loop				;jump back
dvander@121
   526
	//:done
dvander@121
   527
	IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
dvander@121
   528
	IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
dvander@121
   529
	jitoffs_t loop1 = jit->get_outputpos();
dvander@121
   530
	IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
dvander@121
   531
	jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
dvander@121
   532
	IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
dvander@121
   533
	IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
faluco@134
   534
	IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
faluco@134
   535
	IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
dvander@121
   536
	IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
dvander@121
   537
	IA32_Send_Jump8_Here(jit, done1);
dvander@121
   538
dvander@121
   539
	/* Test if we have heap space for this */
dvander@121
   540
	//mov eax, [esi+info.heap]	;get heap pointer
dvander@131
   541
	//lea eax, [eax+edx*4]		;new heap pointer
dvander@121
   542
	//cmp eax, <hlw>			;compare to heap low
dvander@121
   543
	//jbe :error				;die if we hit this (it should always be >)
dvander@121
   544
	//add eax, ebp				;relocate to stack
dvander@121
   545
	//cmp eax, edi				;die if above the stack pointer
dvander@121
   546
	//jae :error
dvander@121
   547
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@131
   548
	IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
dvander@121
   549
	IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
dvander@121
   550
	IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
faluco@134
   551
	IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
dvander@121
   552
	IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
dvander@121
   553
	IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
dvander@121
   554
	
dvander@121
   555
	/* Prepare for indirection iteration */
dvander@121
   556
	//mov eax, [esi+info.heap]	;get heap pointer
dvander@131
   557
	//lea ebx, [eax+edx*4]		;new heap pointer
dvander@121
   558
	//mov [esi+info.heap], ebx	;store back
dvander@121
   559
	//push eax					;save heap pointer - we need it
dvander@121
   560
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
dvander@131
   561
	IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
dvander@121
   562
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
dvander@121
   563
	IA32_Push_Reg(jit, REG_EAX);
dvander@131
   564
faluco@134
   565
	WriteOp_Tracker_Push_Reg(jit, REG_EDX);
dvander@121
   566
	
dvander@121
   567
	/* This part is too messy to do in straight assembly.
dvander@121
   568
	 * I'm letting the compiler handle it and thus it's in C.
dvander@121
   569
	 */
dvander@121
   570
	//lea ebx, [ebp+eax]		;get base pointer
dvander@124
   571
	//push dword [esp-8]		;push autozero
dvander@124
   572
	//push dword [esp-8]		;push dimension count
dvander@121
   573
	//push edi					;push dim array
dvander@121
   574
	//push ebx
dvander@121
   575
	//call GenerateArrayIndirectionVectors
dvander@121
   576
	//add esp, 4*3
dvander@121
   577
	IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
dvander@124
   578
	IA32_Push_Rm_Disp8_ESP(jit, 8);
dvander@124
   579
	IA32_Push_Rm_Disp8_ESP(jit, 8);
dvander@121
   580
	IA32_Push_Reg(jit, REG_EDI);
dvander@121
   581
	IA32_Push_Reg(jit, REG_EBX);
dvander@121
   582
	IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
dvander@124
   583
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
dvander@121
   584
dvander@121
   585
	/* Store the heap pointer back into the stack */
dvander@121
   586
	//pop eax					;restore heap pointer
dvander@121
   587
	//pop ecx					;restore param count
dvander@121
   588
	//lea edi, [edi+ecx*4-4]	;pop params-4 off the stack
dvander@121
   589
	//mov [edi], eax			;store back the heap pointer
dvander@121
   590
	IA32_Pop_Reg(jit, REG_EAX);
dvander@121
   591
	IA32_Pop_Reg(jit, REG_ECX);
dvander@121
   592
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
dvander@121
   593
	IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
dvander@121
   594
dvander@121
   595
	/* Return to caller */
dvander@124
   596
	//pop edx
dvander@121
   597
	//pop eax
dvander@121
   598
	//pop ebx
dvander@121
   599
	//ret
dvander@124
   600
	IA32_Pop_Reg(jit, REG_ECX);
dvander@121
   601
	IA32_Pop_Reg(jit, REG_EAX);
dvander@121
   602
	IA32_Pop_Reg(jit, REG_EBX);
dvander@121
   603
	IA32_Return(jit);
dvander@120
   604
}
dvander@120
   605
dvander@105
   606
void WriteOp_Sysreq_N_Function(JitWriter *jit)
dvander@105
   607
{
dvander@105
   608
	/* The big daddy of opcodes.
dvander@105
   609
	 * eax - num_params
dvander@105
   610
	 * ecx - native index
dvander@105
   611
	 */
dvander@105
   612
	CompData *data = (CompData *)jit->data;
dvander@105
   613
dvander@105
   614
	/* store the number of parameters on the stack */
dvander@105
   615
	//mov [edi-4], eax
dvander@105
   616
	//sub edi, 4
dvander@105
   617
	IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
dvander@105
   618
	IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
dvander@105
   619
dvander@105
   620
	/* save registers we will need */
dvander@105
   621
	//push eax	; num_params for stack popping
dvander@105
   622
	//push edx
dvander@105
   623
	IA32_Push_Reg(jit, REG_EAX);
dvander@105
   624
	IA32_Push_Reg(jit, AMX_REG_ALT);
dvander@105
   625
dvander@105
   626
	/* push some callback stuff */
dvander@105
   627
	//push edi		; stack
dvander@105
   628
	//push ecx		; native index
dvander@105
   629
	IA32_Push_Reg(jit, AMX_REG_STK);
dvander@105
   630
	IA32_Push_Reg(jit, REG_ECX);
dvander@105
   631
dvander@105
   632
	/* Relocate stack, heap, frm information, then store back */
faluco@125
   633
	//mov eax, [esi+context]
dvander@105
   634
	//mov ecx, [esi+hea]
faluco@125
   635
	//sub edi, ebp
dvander@105
   636
	//mov [eax+hp], ecx
faluco@125
   637
	//mov ecx, [esi]
dvander@105
   638
	//mov [eax+sp], edi
dvander@105
   639
	//mov [eax+frm], ecx
faluco@125
   640
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
dvander@105
   641
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
faluco@125
   642
	IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@105
   643
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
faluco@125
   644
	IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
dvander@105
   645
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
dvander@105
   646
	IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
dvander@105
   647
dvander@105
   648
	/* finally, push the last parameter and make the call */
dvander@105
   649
	//push eax		; context
dvander@105
   650
	//call NativeCallback
dvander@105
   651
	IA32_Push_Reg(jit, REG_EAX);
dvander@105
   652
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
dvander@113
   653
	if (!data->debug)
dvander@113
   654
	{
dvander@113
   655
		IA32_Write_Jump32_Abs(jit, call, NativeCallback);
dvander@113
   656
	} else {
dvander@113
   657
		IA32_Write_Jump32_Abs(jit, call, NativeCallback_Debug);
dvander@113
   658
	}
dvander@112
   659
dvander@112
   660
	/* Test for error */
dvander@112
   661
	//mov ecx, [esi+context]
dvander@112
   662
	//cmp [ecx+err], 0
dvander@112
   663
	//jnz :error
dvander@112
   664
	IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
faluco@125
   665
	IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, err), 0);
dvander@112
   666
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
dvander@105
   667
dvander@105
   668
	/* restore what we damaged */
dvander@105
   669
	//add esp, 4*3
dvander@105
   670
	//add edi, ebp
dvander@105
   671
	//pop edx
dvander@105
   672
	//pop ecx	; num_params
dvander@105
   673
	IA32_Add_Rm_Imm8(jit, REG_ESP, 4*3, MOD_REG);
faluco@125
   674
	IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
dvander@105
   675
	IA32_Pop_Reg(jit, AMX_REG_ALT);
dvander@105
   676
	IA32_Pop_Reg(jit, REG_ECX);
dvander@105
   677
dvander@105
   678
	/* pop the AMX stack.  do not check the margins.
dvander@105
   679
	 * Note that this is not a true macro - we don't bother to
dvander@105
   680
	 * set ALT here because nothing will be using it.
dvander@105
   681
	 */
dvander@105
   682
	//lea edi, [edi+ecx*4+4]
dvander@105
   683
	IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
dvander@105
   684
dvander@105
   685
	//ret
dvander@105
   686
	IA32_Return(jit);
dvander@105
   687
}
dvander@105
   688
faluco@134
   689
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
faluco@134
   690
{
faluco@134
   691
	CompData *data = (CompData *)jit->data;
faluco@134
   692
faluco@134
   693
	//:TODO: optimize reg usage, i dont like it.
faluco@134
   694
faluco@134
   695
	/* Save registers that may be damaged by the call */
faluco@134
   696
	//push eax
faluco@134
   697
	//push edx
faluco@134
   698
	//push ecx
faluco@134
   699
	//push <reg>
faluco@134
   700
	IA32_Push_Reg(jit, AMX_REG_PRI);
faluco@134
   701
	IA32_Push_Reg(jit, AMX_REG_ALT);
faluco@134
   702
	IA32_Push_Reg(jit, AMX_REG_TMP);
faluco@134
   703
	if (reg != REG_ECX)
faluco@134
   704
	{
faluco@134
   705
		IA32_Push_Reg(jit, reg);
faluco@134
   706
	}
faluco@134
   707
faluco@134
   708
	/* Get the context ptr, push it and call the check */
faluco@134
   709
	//mov eax, [esi+context]
faluco@134
   710
	//push eax
faluco@134
   711
	//call JIT_VerifyOrAllocateTracker
faluco@134
   712
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
faluco@134
   713
	IA32_Push_Reg(jit, REG_EAX);
faluco@134
   714
	jitoffs_t call = IA32_Call_Imm32(jit, 0);
faluco@134
   715
	IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker);
faluco@134
   716
faluco@134
   717
	/* Check for errors */
faluco@134
   718
	//pop eax
faluco@134
   719
	//cmp [eax+err], 0
faluco@134
   720
	//jnz :error
faluco@134
   721
	IA32_Pop_Reg(jit, REG_EAX);
faluco@134
   722
	IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0);
faluco@134
   723
	IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds);
faluco@134
   724
faluco@134
   725
	/* Push the register into the stack and increment pCur */
faluco@134
   726
	//pop ecx
faluco@134
   727
	//mov edx, [eax+vm[]]
faluco@134
   728
	//mov eax, [edx+pcur]
faluco@134
   729
	//lea ecx, [ecx*4]	; we want the count in bytes not in cells
faluco@134
   730
	//mov [eax], ecx
faluco@134
   731
	//add [edx+pcur], 4
faluco@134
   732
	IA32_Pop_Reg(jit, REG_ECX);
faluco@134
   733
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
faluco@134
   734
	IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
faluco@134
   735
	IA32_Lea_Reg_RegMultImm32(jit, REG_ECX, REG_ECX, SCALE4, 0);
faluco@134
   736
	IA32_Mov_Rm_Reg(jit, REG_EAX, REG_ECX, MOD_MEM_REG);
faluco@134
   737
	IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
faluco@134
   738
faluco@134
   739
	/* Restore PRI, ALT and STK */
faluco@134
   740
	//pop ecx
faluco@134
   741
	//pop edx
faluco@134
   742
	//pop eax
faluco@134
   743
	if (reg != REG_ECX)
faluco@134
   744
	{
faluco@134
   745
		IA32_Pop_Reg(jit, AMX_REG_ALT);
faluco@134
   746
	} else {
faluco@134
   747
		IA32_Shr_Rm_Imm8(jit, REG_ECX, 2, MOD_REG);
faluco@134
   748
	}
faluco@134
   749
	IA32_Pop_Reg(jit, AMX_REG_TMP);
faluco@134
   750
	IA32_Pop_Reg(jit, AMX_REG_PRI);
faluco@134
   751
}
faluco@134
   752
faluco@130
   753
void JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
faluco@130
   754
{
faluco@130
   755
	tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
faluco@130
   756
faluco@130
   757
	if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
faluco@130
   758
	{
faluco@130
   759
		ctx->err = SP_ERROR_TRACKER_BOUNDS;
faluco@130
   760
		return;
faluco@130
   761
	}
faluco@130
   762
faluco@130
   763
	if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
faluco@130
   764
	{
faluco@130
   765
		size_t disp = trk->size - 1;
faluco@130
   766
		trk->size *= 2;
faluco@134
   767
		trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
faluco@130
   768
faluco@130
   769
		if (!trk->pBase)
faluco@130
   770
		{
faluco@130
   771
			ctx->err = SP_ERROR_TRACKER_BOUNDS;
faluco@130
   772
			return;
faluco@130
   773
		}
faluco@130
   774
faluco@130
   775
		trk->pCur = trk->pBase + disp;
faluco@130
   776
	}
faluco@130
   777
}
faluco@130
   778
faluco@130
   779
void JIT_VerifyLowBoundTracker(sp_context_t *ctx)
faluco@130
   780
{
faluco@130
   781
	tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
faluco@130
   782
faluco@130
   783
	if (trk->pCur <= trk->pBase)
faluco@130
   784
	{
faluco@130
   785
		ctx->err = SP_ERROR_TRACKER_BOUNDS;
faluco@130
   786
	}
faluco@130
   787
}