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