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