extensions/bintools/jit_call.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 22 17:24:48 2007 +0000 (2007-06-22)
changeset 1002 786f5abf93ea
parent 831 1995c0dd5c04
child 1030 bff3180e56e8
permissions -rw-r--r--
fixed a bug where the "keyOnly" parameter to KvGotoNextKey was read backwards
faluco@739
     1
/**
faluco@739
     2
 * vim: set ts=4 :
faluco@739
     3
 * ===============================================================
ds@757
     4
 * SourceMod BinTools Extension
ds@757
     5
 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
faluco@739
     6
 * ===============================================================
faluco@739
     7
 *
ds@757
     8
 * This program is free software; you can redistribute it and/or
ds@757
     9
 * modify it under the terms of the GNU General Public License
ds@757
    10
 * as published by the Free Software Foundation; either version 2
ds@757
    11
 * of the License, or (at your option) any later version.
ds@757
    12
 * This program is distributed in the hope that it will be useful,
ds@757
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ds@757
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ds@757
    15
 * GNU General Public License for more details.
faluco@739
    16
 * 
ds@757
    17
 * You should have received a copy of the GNU General Public License
ds@757
    18
 * along with this program; if not, write to the Free Software
ds@757
    19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
faluco@739
    20
 *
faluco@739
    21
 * Version: $Id$
faluco@739
    22
 */
faluco@739
    23
faluco@739
    24
#include <sm_platform.h>
faluco@739
    25
#include "extension.h"
faluco@739
    26
#include <jit_helpers.h>
faluco@739
    27
#include <x86_macros.h>
faluco@739
    28
#include "jit_call.h"
faluco@739
    29
faluco@739
    30
jit_uint32_t g_StackUsage = 0;
faluco@739
    31
jit_uint32_t g_RegDecoder = 0;
faluco@739
    32
faluco@739
    33
/********************
faluco@739
    34
 * Assembly Helpers *
faluco@739
    35
 ********************/
faluco@739
    36
faluco@739
    37
inline jit_uint8_t _DecodeRegister3(jit_uint32_t val)
faluco@739
    38
{
faluco@739
    39
	switch (val % 3)
faluco@739
    40
	{
faluco@739
    41
	case 0:
faluco@739
    42
		{
faluco@739
    43
			return REG_EAX;
faluco@739
    44
		}
faluco@739
    45
	case 1:
faluco@739
    46
		{
faluco@739
    47
			return REG_EDX;
faluco@739
    48
		}
faluco@739
    49
	case 2:
faluco@739
    50
		{
faluco@739
    51
			return REG_ECX;
faluco@739
    52
		}
faluco@739
    53
	}
faluco@739
    54
faluco@739
    55
	/* Should never happen */
faluco@739
    56
	return 0xFF;
faluco@739
    57
}
faluco@739
    58
faluco@739
    59
/********************
faluco@739
    60
 * Assembly Opcodes *
faluco@739
    61
 ********************/
faluco@739
    62
faluco@739
    63
inline void Write_Execution_Prologue(JitWriter *jit, bool is_void, bool has_params)
faluco@739
    64
{
faluco@739
    65
	//push ebp
faluco@739
    66
	//mov ebp, esp
faluco@739
    67
	//if !is_void
faluco@739
    68
	// push edi
faluco@739
    69
	// mov edi, [ebp+12]
faluco@739
    70
	//if has_params
faluco@739
    71
	// push ebx
faluco@739
    72
	// mov ebx, [ebp+8]
faluco@739
    73
	IA32_Push_Reg(jit, REG_EBP);
faluco@739
    74
	IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
faluco@739
    75
	if (!is_void)
faluco@739
    76
	{
faluco@739
    77
		IA32_Push_Reg(jit, REG_EDI);
faluco@739
    78
		IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EBP, 12);
faluco@739
    79
	}
faluco@739
    80
	if (has_params)
faluco@739
    81
	{
faluco@739
    82
		IA32_Push_Reg(jit, REG_EBX);
faluco@739
    83
		IA32_Mov_Reg_Rm_Disp8(jit, REG_EBX, REG_EBP, 8);
faluco@739
    84
	}
faluco@739
    85
}
faluco@739
    86
faluco@739
    87
inline void Write_Function_Epilogue(JitWriter *jit, bool is_void, bool has_params)
faluco@739
    88
{
faluco@739
    89
	//if has_params
faluco@739
    90
	// pop ebx
faluco@739
    91
	//if !is_void
faluco@739
    92
	// pop edi
faluco@739
    93
	//mov esp, ebp
faluco@739
    94
	//pop ebp
faluco@739
    95
	//ret
faluco@739
    96
	if (has_params)
faluco@739
    97
	{
faluco@739
    98
		IA32_Pop_Reg(jit, REG_EBX);
faluco@739
    99
	}
faluco@739
   100
	if (!is_void)
faluco@739
   101
	{
faluco@739
   102
		IA32_Pop_Reg(jit, REG_EDI);
faluco@739
   103
	}
faluco@739
   104
	IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBP, MOD_REG);
faluco@739
   105
	IA32_Pop_Reg(jit, REG_EBP);
faluco@739
   106
	IA32_Return(jit);
faluco@739
   107
}
faluco@739
   108
faluco@739
   109
inline void Write_PushPOD(JitWriter *jit, const PassEncode *pEnc)
faluco@739
   110
{
faluco@739
   111
	jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++);
faluco@739
   112
faluco@739
   113
	if (pEnc->info.flags & PASSFLAG_BYVAL)
faluco@739
   114
	{
faluco@739
   115
		switch (pEnc->info.size)
faluco@739
   116
		{
faluco@739
   117
		case 1:
faluco@739
   118
			{
faluco@831
   119
				//movzx reg, BYTE PTR [ebx+<offset>]
faluco@739
   120
				//push reg
faluco@739
   121
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   122
				{
faluco@831
   123
					IA32_Movzx_Reg32_Rm8_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   124
				} else if (!pEnc->offset) {
faluco@831
   125
					IA32_Movzx_Reg32_Rm8(jit, reg, REG_EBX, MOD_MEM_REG);
faluco@739
   126
				} else {
faluco@831
   127
					IA32_Movzx_Reg32_Rm8_Disp32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   128
				}
faluco@739
   129
				IA32_Push_Reg(jit, reg);
faluco@739
   130
faluco@739
   131
				g_StackUsage += 4;
faluco@739
   132
				break;
faluco@739
   133
			}
faluco@739
   134
		case 2:
faluco@739
   135
			{
faluco@831
   136
				//movzx reg, WORD PTR [ebx+<offset>]
faluco@739
   137
				//push reg
faluco@739
   138
				jit->write_ubyte(IA32_16BIT_PREFIX);
faluco@739
   139
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   140
				{
faluco@831
   141
					IA32_Movzx_Reg32_Rm16_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   142
				} else if (!pEnc->offset) {
faluco@831
   143
					IA32_Movzx_Reg32_Rm16(jit, reg, REG_EBX, MOD_MEM_REG);
faluco@739
   144
				} else {
faluco@831
   145
					IA32_Movzx_Reg32_Rm16_Disp32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   146
				}
faluco@739
   147
				IA32_Push_Reg(jit, reg);
faluco@739
   148
faluco@739
   149
				g_StackUsage += 4;
faluco@739
   150
				break;
faluco@739
   151
			}
faluco@739
   152
		case 4:
faluco@739
   153
			{
faluco@739
   154
				//mov reg, DWORD PTR [ebx+<offset>]
faluco@739
   155
				//push reg
faluco@739
   156
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   157
				{
faluco@739
   158
					IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   159
				} else if (!pEnc->offset) {
faluco@739
   160
					IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG);
faluco@739
   161
				} else {
faluco@739
   162
					IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   163
				}
faluco@739
   164
				IA32_Push_Reg(jit, reg);
faluco@739
   165
faluco@739
   166
				g_StackUsage += 4;
faluco@739
   167
				break;
faluco@739
   168
			}
faluco@739
   169
		case 8:
faluco@739
   170
			{
faluco@739
   171
				//mov reg, DWORD PTR [ebx+<offset>+4]
faluco@739
   172
				//mov reg2, DWORD PTR [ebx+<offset>]
faluco@739
   173
				//push reg
faluco@739
   174
				//push reg2
faluco@739
   175
				jit_uint8_t reg2 = _DecodeRegister3(g_RegDecoder++);
faluco@739
   176
faluco@739
   177
				if (pEnc->offset+4 < SCHAR_MAX)
faluco@739
   178
				{
faluco@739
   179
					IA32_Mov_Reg_Rm_Disp8(jit, reg, REG_EBX, (jit_int8_t)(pEnc->offset+4));
faluco@739
   180
				} else {
faluco@739
   181
					IA32_Mov_Reg_Rm_Disp32(jit, reg, REG_EBX, pEnc->offset+4);
faluco@739
   182
				}
faluco@739
   183
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   184
				{
faluco@739
   185
					IA32_Mov_Reg_Rm_Disp8(jit, reg2, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   186
				} else if (!pEnc->offset) {
faluco@739
   187
					IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG);
faluco@739
   188
				} else {
faluco@739
   189
					IA32_Mov_Reg_Rm_Disp32(jit, reg2, REG_EBX, pEnc->offset);
faluco@739
   190
				}
faluco@739
   191
				IA32_Push_Reg(jit, reg);
faluco@739
   192
				IA32_Push_Reg(jit, reg2);
faluco@739
   193
faluco@739
   194
				g_StackUsage += 8;
faluco@739
   195
				break;
faluco@739
   196
			}
faluco@739
   197
		}
faluco@739
   198
	} else if (pEnc->info.flags & PASSFLAG_BYREF) {
faluco@739
   199
		//lea reg, [ebx+<offset>]
faluco@739
   200
		//push reg
faluco@739
   201
		if (!pEnc->offset)
faluco@739
   202
		{
faluco@739
   203
			IA32_Push_Reg(jit, REG_EBX);
faluco@739
   204
			g_StackUsage += 4;
faluco@739
   205
			return;
faluco@739
   206
		}
faluco@739
   207
		if (pEnc->offset < SCHAR_MAX)
faluco@739
   208
		{
faluco@739
   209
			IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   210
		} else {
faluco@739
   211
			IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   212
		}
faluco@739
   213
		IA32_Push_Reg(jit, reg);
faluco@739
   214
faluco@739
   215
		g_StackUsage += 4;
faluco@739
   216
	}
faluco@739
   217
}
faluco@739
   218
faluco@739
   219
inline void Write_PushFloat(JitWriter *jit, const PassEncode *pEnc)
faluco@739
   220
{
faluco@739
   221
	if (pEnc->info.flags & PASSFLAG_BYVAL)
faluco@739
   222
	{
faluco@739
   223
		switch (pEnc->info.size)
faluco@739
   224
		{
faluco@739
   225
		case 4:
faluco@739
   226
			{
faluco@739
   227
				//fld DWORD PTR [ebx+<offset>]
faluco@739
   228
				//push reg
faluco@739
   229
				//fstp DWORD PTR [esp]
faluco@739
   230
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   231
				{
faluco@739
   232
					IA32_Fld_Mem32_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@831
   233
				} else if (!pEnc->offset) {
faluco@831
   234
					IA32_Fld_Mem32(jit, REG_EBX);
faluco@739
   235
				} else {
faluco@739
   236
					IA32_Fld_Mem32_Disp32(jit, REG_EBX, pEnc->offset);
faluco@739
   237
				}
faluco@739
   238
				IA32_Push_Reg(jit, _DecodeRegister3(g_RegDecoder++));
faluco@831
   239
				IA32_Fstp_Mem32_ESP(jit);
faluco@739
   240
				g_StackUsage += 4;
faluco@739
   241
				break;
faluco@739
   242
			}
faluco@739
   243
		case 8:
faluco@739
   244
			{
faluco@739
   245
				//fld QWORD PTR [ebx+<offset>]
faluco@739
   246
				//sub esp, 8
faluco@739
   247
				//fstp QWORD PTR [esp]
faluco@739
   248
				if (pEnc->offset < SCHAR_MAX)
faluco@739
   249
				{
faluco@739
   250
					IA32_Fld_Mem64_Disp8(jit, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@831
   251
				} else if (!pEnc->offset) {
faluco@831
   252
					IA32_Fld_Mem64(jit, REG_EBX);
faluco@739
   253
				} else {
faluco@739
   254
					IA32_Fld_Mem64_Disp32(jit, REG_EBX, pEnc->offset);
faluco@739
   255
				}
faluco@739
   256
				IA32_Sub_Rm_Imm8(jit, REG_ESP, 8, MOD_REG);
faluco@831
   257
				IA32_Fstp_Mem64_ESP(jit);
faluco@739
   258
				g_StackUsage += 8;
faluco@739
   259
				break;
faluco@739
   260
			}
faluco@739
   261
		}
faluco@739
   262
	} else if (pEnc->info.flags & PASSFLAG_BYREF) {
faluco@739
   263
		//lea reg, [ebx+<offset>]
faluco@739
   264
		//push reg
faluco@739
   265
		if (!pEnc->offset)
faluco@739
   266
		{
faluco@739
   267
			IA32_Push_Reg(jit, REG_EBX);
faluco@739
   268
			g_StackUsage += 4;
faluco@739
   269
			return;
faluco@739
   270
		}
faluco@739
   271
faluco@739
   272
		jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++);
faluco@739
   273
		if (pEnc->offset < SCHAR_MAX)
faluco@739
   274
		{
faluco@739
   275
			IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   276
		} else {
faluco@739
   277
			IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   278
		}
faluco@739
   279
		IA32_Push_Reg(jit, reg);
faluco@739
   280
faluco@739
   281
		g_StackUsage += 4;
faluco@739
   282
	}
faluco@739
   283
}
faluco@739
   284
faluco@739
   285
inline void Write_PushObject(JitWriter *jit, const PassEncode *pEnc)
faluco@739
   286
{
faluco@739
   287
	if (pEnc->info.flags & PASSFLAG_BYVAL)
faluco@739
   288
	{
faluco@739
   289
#ifdef PLATFORM_POSIX
faluco@739
   290
		if (pEnc->info.flags & PASSFLAG_ODTOR)
faluco@739
   291
		{
faluco@739
   292
			goto push_byref;
faluco@739
   293
		}
faluco@739
   294
#endif
faluco@739
   295
		jit_uint32_t dwords = pEnc->info.size >> 2;
faluco@739
   296
		jit_uint32_t bytes = pEnc->info.size & 0x3;
faluco@739
   297
faluco@739
   298
		//sub esp, <size>
faluco@739
   299
		//cld
faluco@739
   300
		//push edi
faluco@739
   301
		//push esi
faluco@739
   302
		//lea edi, [esp+8]
faluco@739
   303
		//lea esi, [ebx+<offs>]
faluco@739
   304
		//if dwords
faluco@739
   305
		// mov ecx, <dwords>
faluco@739
   306
		// rep movsd
faluco@739
   307
		//if bytes
faluco@739
   308
		// mov ecx, <bytes>
faluco@739
   309
		// rep movsb
faluco@739
   310
		//pop esi
faluco@739
   311
		//pop edi
faluco@739
   312
		if (pEnc->info.size < SCHAR_MAX)
faluco@739
   313
		{
faluco@739
   314
			IA32_Sub_Rm_Imm8(jit, REG_ESP, (jit_int8_t)pEnc->info.size, MOD_REG);
faluco@739
   315
		} else {
faluco@739
   316
			IA32_Sub_Rm_Imm32(jit, REG_ESP, pEnc->info.size, MOD_REG);
faluco@739
   317
		}
faluco@739
   318
		IA32_Cld(jit);
faluco@739
   319
		IA32_Push_Reg(jit, REG_EDI);
faluco@739
   320
		IA32_Push_Reg(jit, REG_ESI);
faluco@739
   321
		IA32_Lea_Reg_DispRegMultImm8(jit, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8);
faluco@739
   322
		if (pEnc->offset < SCHAR_MAX)
faluco@739
   323
		{
faluco@739
   324
			IA32_Lea_DispRegImm8(jit, REG_ESI, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   325
		} else if (!pEnc->offset) {
faluco@739
   326
			IA32_Mov_Reg_Rm(jit, REG_ESI, REG_EBX, MOD_REG);
faluco@739
   327
		} else {
faluco@739
   328
			IA32_Lea_DispRegImm32(jit, REG_ESI, REG_EBX, pEnc->offset);
faluco@739
   329
		}
faluco@739
   330
		if (dwords)
faluco@739
   331
		{
faluco@739
   332
			IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords);
faluco@739
   333
			IA32_Rep(jit);
faluco@739
   334
			IA32_Movsd(jit);
faluco@739
   335
		}
faluco@739
   336
		if (bytes)
faluco@739
   337
		{
faluco@739
   338
			IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes);
faluco@739
   339
			IA32_Rep(jit);
faluco@739
   340
			IA32_Movsb(jit);
faluco@739
   341
		}
faluco@739
   342
		IA32_Pop_Reg(jit, REG_ESI);
faluco@739
   343
		IA32_Pop_Reg(jit, REG_EDI);
faluco@739
   344
faluco@739
   345
		g_StackUsage += pEnc->info.size;
faluco@739
   346
	} else if (pEnc->info.flags & PASSFLAG_BYREF) {
faluco@739
   347
#ifdef PLATFORM_POSIX
faluco@739
   348
push_byref:
faluco@739
   349
#endif
faluco@739
   350
		if (!pEnc->offset)
faluco@739
   351
		{
faluco@739
   352
			IA32_Push_Reg(jit, REG_EBX);
faluco@739
   353
			g_StackUsage += 4;
faluco@739
   354
			return;
faluco@739
   355
		}
faluco@739
   356
faluco@739
   357
		//lea reg, [ebx+<offset>]
faluco@739
   358
		//push reg
faluco@739
   359
		jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++);
faluco@739
   360
		if (pEnc->offset < SCHAR_MAX)
faluco@739
   361
		{
faluco@739
   362
			IA32_Lea_DispRegImm8(jit, reg, REG_EBX, (jit_int8_t)pEnc->offset);
faluco@739
   363
		} else {
faluco@739
   364
			IA32_Lea_DispRegImm32(jit, reg, REG_EBX, pEnc->offset);
faluco@739
   365
		}
faluco@739
   366
		IA32_Push_Reg(jit, reg);
faluco@739
   367
faluco@739
   368
		g_StackUsage += 4;
faluco@739
   369
	}
faluco@739
   370
}
faluco@739
   371
faluco@739
   372
inline void Write_PushThisPtr(JitWriter *jit)
faluco@739
   373
{
faluco@739
   374
#ifdef PLATFORM_POSIX
faluco@739
   375
	//mov reg, [ebx]
faluco@739
   376
	//push reg
faluco@739
   377
	jit_uint8_t reg = _DecodeRegister3(g_RegDecoder++);
faluco@739
   378
faluco@739
   379
	IA32_Mov_Reg_Rm(jit, reg, REG_EBX, MOD_MEM_REG);
faluco@739
   380
	IA32_Push_Reg(jit, reg);
faluco@739
   381
faluco@739
   382
	g_StackUsage += 4;
faluco@739
   383
#elif defined PLATFORM_WINDOWS
faluco@739
   384
	//mov ecx, [ebx]
faluco@739
   385
	IA32_Mov_Reg_Rm(jit, REG_ECX, REG_EBX, MOD_MEM_REG);
faluco@739
   386
#endif
faluco@739
   387
}
faluco@739
   388
faluco@739
   389
inline void Write_PushRetBuffer(JitWriter *jit)
faluco@739
   390
{
faluco@739
   391
	//push edi
faluco@739
   392
	IA32_Push_Reg(jit, REG_EDI);
faluco@739
   393
}
faluco@739
   394
faluco@739
   395
inline void Write_CallFunction(JitWriter *jit, FuncAddrMethod method, CallWrapper *pWrapper)
faluco@739
   396
{
faluco@739
   397
	if (method == FuncAddr_Direct)
faluco@739
   398
	{
faluco@739
   399
		//call <addr>
faluco@739
   400
		jitoffs_t call = IA32_Call_Imm32(jit, 0);
faluco@739
   401
		IA32_Write_Jump32_Abs(jit, call, pWrapper->m_Addrs[ADDR_CALLEE]);
faluco@739
   402
	} else if (method == FuncAddr_VTable) {
faluco@739
   403
		//*(this + thisOffs + vtblOffs)[vtblIdx]
faluco@739
   404
		//mov edx, [ebx]
faluco@739
   405
		//mov eax, [edx+<thisOffs>+<vtblOffs>]
faluco@739
   406
		//mov edx, [eax+<vtblIdx>*4]
faluco@739
   407
		//call edx
faluco@739
   408
		jit_uint32_t total_offs = pWrapper->m_VtInfo.thisOffs + pWrapper->m_VtInfo.vtblOffs;
faluco@739
   409
		jit_uint32_t vfunc_pos = pWrapper->m_VtInfo.vtblIdx * 4;
faluco@739
   410
faluco@739
   411
		IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EBX, MOD_MEM_REG);
faluco@739
   412
		if (total_offs < SCHAR_MAX)
faluco@739
   413
		{
faluco@739
   414
			IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, (jit_int8_t)total_offs);
faluco@739
   415
		} else if (!total_offs) {
faluco@739
   416
			IA32_Mov_Reg_Rm(jit, REG_EAX, REG_EDX, MOD_MEM_REG);
faluco@739
   417
		} else {
faluco@739
   418
			IA32_Mov_Reg_Rm_Disp32(jit, REG_EAX, REG_EDX, total_offs);
faluco@739
   419
		}
faluco@739
   420
		if (vfunc_pos < SCHAR_MAX)
faluco@739
   421
		{
faluco@739
   422
			IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, (jit_int8_t)vfunc_pos);
faluco@739
   423
		} else if (!vfunc_pos) {
faluco@739
   424
			IA32_Mov_Reg_Rm(jit, REG_EDX, REG_EAX, MOD_MEM_REG);
faluco@739
   425
		} else {
faluco@739
   426
			IA32_Mov_Reg_Rm_Disp32(jit, REG_EDX, REG_EAX, vfunc_pos);
faluco@739
   427
		}
faluco@739
   428
		IA32_Call_Reg(jit, REG_EDX);
faluco@739
   429
	}
faluco@739
   430
}
faluco@739
   431
faluco@739
   432
inline void Write_RectifyStack(JitWriter *jit, jit_uint32_t value)
faluco@739
   433
{
faluco@739
   434
	//add esp, <value>
faluco@739
   435
	if (value < SCHAR_MAX)
faluco@739
   436
	{
faluco@739
   437
		IA32_Add_Rm_Imm8(jit, REG_ESP, (jit_int8_t)value, MOD_REG);
faluco@739
   438
	} else {
faluco@739
   439
		IA32_Add_Rm_Imm32(jit, REG_ESP, value, MOD_REG);
faluco@739
   440
	}
faluco@739
   441
}
faluco@739
   442
faluco@739
   443
inline void Write_MovRet2Buf(JitWriter *jit, const PassInfo *pRet)
faluco@739
   444
{
faluco@739
   445
	if (pRet->type == PassType_Float)
faluco@739
   446
	{
faluco@739
   447
		switch (pRet->size)
faluco@739
   448
		{
faluco@739
   449
		case 4:
faluco@739
   450
			{
faluco@739
   451
				//fstp DWORD PTR [edi]
faluco@831
   452
				IA32_Fstp_Mem32(jit, REG_EDI);
faluco@739
   453
				break;
faluco@739
   454
			}
faluco@739
   455
		case 8:
faluco@739
   456
			{
faluco@739
   457
				//fstp QWORD PTR [edi]
faluco@831
   458
				IA32_Fstp_Mem64(jit, REG_EDI);
faluco@739
   459
				break;
faluco@739
   460
			}
faluco@739
   461
		}
faluco@739
   462
		return;
faluco@739
   463
	}
faluco@739
   464
faluco@739
   465
	switch (pRet->size)
faluco@739
   466
	{
faluco@739
   467
	case 1:
faluco@739
   468
		{
faluco@739
   469
			//mov BYTE PTR [edi], al
faluco@739
   470
			IA32_Mov_Rm8_Reg8(jit, REG_EDI, REG_EAX, MOD_MEM_REG);
faluco@739
   471
			break;
faluco@739
   472
		}
faluco@739
   473
	case 2:
faluco@739
   474
		{
faluco@739
   475
			//mov WORD PTR [edi], ax
faluco@739
   476
			jit->write_ubyte(IA32_16BIT_PREFIX);
faluco@739
   477
			IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG);
faluco@739
   478
			break;
faluco@739
   479
		}
faluco@739
   480
	case 4:
faluco@739
   481
		{
faluco@739
   482
			//mov DWORD PTR [edi], eax
faluco@739
   483
			IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG);
faluco@739
   484
			break;
faluco@739
   485
		}
faluco@739
   486
	case 8:
faluco@739
   487
		{
faluco@739
   488
			//mov DWORD PTR [edi], eax
faluco@739
   489
			//mov DWORD PTR [edi+4], edx
faluco@739
   490
			IA32_Mov_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_MEM_REG);
faluco@739
   491
			IA32_Mov_Rm_Reg_Disp8(jit, REG_EDI, REG_EDX, 4);
faluco@739
   492
			break;
faluco@739
   493
		}
faluco@739
   494
	}
faluco@739
   495
}
faluco@739
   496
faluco@739
   497
/******************************
faluco@739
   498
 * Assembly Compiler Function *
faluco@739
   499
 ******************************/
faluco@739
   500
faluco@739
   501
void JIT_Compile(CallWrapper *pWrapper, FuncAddrMethod method)
faluco@739
   502
{
faluco@739
   503
	JitWriter writer;
faluco@739
   504
	JitWriter *jit = &writer;
faluco@739
   505
faluco@739
   506
	jit_uint32_t CodeSize = 0;
faluco@739
   507
	bool Needs_Retbuf = false;
faluco@739
   508
	CallConvention Convention = pWrapper->GetCallConvention();
faluco@739
   509
	jit_uint32_t ParamCount = pWrapper->GetParamCount();
faluco@739
   510
	const PassInfo *pRet = pWrapper->GetReturnInfo();
ds@744
   511
	bool hasParams = (ParamCount || Convention == CallConv_ThisCall);
faluco@739
   512
faluco@739
   513
	writer.outbase = NULL;
faluco@739
   514
	writer.outptr = NULL;
faluco@739
   515
faluco@739
   516
jit_rewind:
faluco@739
   517
	/* Write function prologue */
ds@744
   518
	Write_Execution_Prologue(jit, (pRet) ? false : true, hasParams);
faluco@739
   519
faluco@739
   520
	/* Write parameter push code */
faluco@739
   521
	for (jit_int32_t i=ParamCount-1; i>=0; i--)
faluco@739
   522
	{
faluco@739
   523
		const PassEncode *pEnc = pWrapper->GetParamInfo(i);
faluco@739
   524
		switch (pEnc->info.type)
faluco@739
   525
		{
faluco@739
   526
		case PassType_Basic:
faluco@739
   527
			{
faluco@739
   528
				Write_PushPOD(jit, pEnc);
faluco@739
   529
				break;
faluco@739
   530
			}
faluco@739
   531
		case PassType_Float:
faluco@739
   532
			{
faluco@739
   533
				Write_PushFloat(jit, pEnc);
faluco@739
   534
				break;
faluco@739
   535
			}
faluco@739
   536
		case PassType_Object:
faluco@739
   537
			{
faluco@739
   538
				Write_PushObject(jit, pEnc);
faluco@739
   539
				break;
faluco@739
   540
			}
faluco@739
   541
		}
faluco@739
   542
	}
faluco@739
   543
faluco@739
   544
	/* Prepare the this ptr if applicable */
faluco@739
   545
	if (Convention == CallConv_ThisCall)
faluco@739
   546
	{
faluco@739
   547
		Write_PushThisPtr(jit);
faluco@739
   548
	}
faluco@739
   549
faluco@739
   550
	/* Skip the return buffer stuff if this is a void function */
faluco@739
   551
	if (!pRet)
faluco@739
   552
	{
faluco@739
   553
		goto skip_retbuffer;
faluco@739
   554
	}
faluco@739
   555
faluco@739
   556
	if ((pRet->type == PassType_Object) && (pRet->flags & PASSFLAG_BYVAL))
faluco@739
   557
	{
faluco@739
   558
#ifdef PLATFORM_POSIX
faluco@739
   559
		Needs_Retbuf = true;
faluco@739
   560
#elif defined PLATFORM_WINDOWS
faluco@739
   561
		if ((Convention == CallConv_ThisCall) ||
faluco@739
   562
			((Convention == CallConv_Cdecl) &&
faluco@739
   563
			((pRet->size > 8) || (pRet->flags & PASSFLAG_ODTOR|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP))))
faluco@739
   564
		{
faluco@739
   565
			Needs_Retbuf = true;
faluco@739
   566
		}
faluco@739
   567
#endif
faluco@739
   568
	}
faluco@739
   569
faluco@739
   570
	/* Prepare the return buffer in case we are returning objects by value. */
faluco@739
   571
	if (Needs_Retbuf)
faluco@739
   572
	{
faluco@739
   573
		Write_PushRetBuffer(jit);
faluco@739
   574
	}
faluco@739
   575
faluco@739
   576
skip_retbuffer:
faluco@739
   577
	/* Write the calling code */
faluco@739
   578
	Write_CallFunction(jit, method, pWrapper);
faluco@739
   579
faluco@739
   580
	/* Clean up the calling stack */
faluco@739
   581
#ifdef PLATFORM_WINDOWS
faluco@739
   582
	if ((ParamCount || Needs_Retbuf) && (Convention == CallConv_Cdecl))
faluco@739
   583
	{
faluco@739
   584
		/* Pop all parameters from the stack + hidden return pointer */
faluco@739
   585
		jit_uint32_t total = (Needs_Retbuf) ? g_StackUsage + sizeof(void *) : g_StackUsage;
faluco@739
   586
		Write_RectifyStack(jit, total);
faluco@739
   587
#elif defined PLATFORM_POSIX
faluco@739
   588
	if (ParamCount)
faluco@739
   589
	{
faluco@739
   590
		/* Pop all parameters from the stack */
faluco@739
   591
		Write_RectifyStack(jit, g_StackUsage);
faluco@739
   592
#endif
faluco@739
   593
	}
faluco@739
   594
faluco@739
   595
	/* Copy the return type to the return buffer if the function is not void */
faluco@739
   596
	if (pRet && !Needs_Retbuf)
faluco@739
   597
	{
faluco@739
   598
		Write_MovRet2Buf(jit, pRet);
faluco@739
   599
	}
faluco@739
   600
faluco@739
   601
	/* Write Function Epilogue */
ds@744
   602
	Write_Function_Epilogue(jit, (pRet) ? false : true, hasParams);
faluco@739
   603
faluco@739
   604
	if (writer.outbase == NULL)
faluco@739
   605
	{
faluco@739
   606
		CodeSize = writer.get_outputpos();
faluco@739
   607
		writer.outbase = (jitcode_t)g_SPEngine->ExecAlloc(CodeSize);
faluco@739
   608
		writer.outptr = writer.outbase;
faluco@739
   609
		pWrapper->m_Addrs[ADDR_CODEBASE] = writer.outbase;
faluco@739
   610
		g_StackUsage = 0;
faluco@739
   611
		g_RegDecoder = 0;
faluco@739
   612
		Needs_Retbuf = false;
faluco@739
   613
		goto jit_rewind;
faluco@739
   614
	}
faluco@739
   615
}