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