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