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