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