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