1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-01-19 08:52:34 +01:00

First version of automatic hookman/hookfunc generation functionality + test

Currently supports (msvc): all params, ret types: integeral, floating-point
Todo: other rettypes (pod/objects, ctors/dtors), gcc support, integration with ISourceHook::AddHook

--HG--
branch : hookman_autogen
extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/hookman_autogen%40532
This commit is contained in:
Pavol Marko 2007-10-21 21:47:53 +00:00
parent f440bbd1b2
commit 7fa9f150fb
10 changed files with 6282 additions and 0 deletions

View File

@ -0,0 +1,1292 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* Contributor(s): Borja "faluco" Ferav (many thanks for assitance!)
* David "BAILOPAN" Anderson
* ============================
*/
// recommended literature:
// http://www.cs.umbc.edu/~chang/cs313.s02/stack.shtml
// http://www.angelcode.com/dev/callconv/callconv.html
// http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_6/CH06-1.html
#include "sourcehook_hookmangen.h"
#include "sourcehook_hookmangen_x86.h"
#include "sh_memory.h"
// :TODO: test BIG vtable indices
namespace SourceHook
{
namespace Impl
{
template <class T>
jit_int32_t DownCastPtr(T ptr)
{
return reinterpret_cast<jit_int32_t>(ptr);
}
jit_uint32_t DownCastSize(size_t size)
{
return static_cast<jit_uint32_t>(size);
}
GenContext::GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr)
: m_Proto(proto), m_VtblOffs(vtbl_offs), m_VtblIdx(vtbl_idx), m_SHPtr(pSHPtr),
m_pHI(NULL), m_HookfuncVfnptr(NULL), m_RegCounter(0)
{
m_pHI = new void*;
m_HookfuncVfnptr = new void*;
m_BuiltPI = new ProtoInfo;
m_BuiltPI_Params = NULL;
m_BuiltPI_Params2 = NULL;
}
GenContext::~GenContext()
{
Clear();
delete m_pHI;
delete m_HookfuncVfnptr;
delete m_BuiltPI;
}
void GenContext::Clear()
{
m_HookFunc.clear();
m_PubFunc.clear();
if (m_BuiltPI_Params)
{
delete m_BuiltPI_Params;
m_BuiltPI_Params = NULL;
}
if (m_BuiltPI_Params2)
{
delete m_BuiltPI_Params2;
m_BuiltPI_Params2 = NULL;
}
}
void GenContext::BuildProtoInfo()
{
m_BuiltPI->convention = m_Proto.GetConvention();
m_BuiltPI->numOfParams = m_Proto.GetNumOfParams();
m_BuiltPI->retPassInfo.size = m_Proto.GetRet().size;
m_BuiltPI->retPassInfo.type = m_Proto.GetRet().type;
m_BuiltPI->retPassInfo.flags = m_Proto.GetRet().flags;
m_BuiltPI->retPassInfo2.pNormalCtor = m_Proto.GetRet().pNormalCtor;
m_BuiltPI->retPassInfo2.pCopyCtor = m_Proto.GetRet().pCopyCtor;
m_BuiltPI->retPassInfo2.pDtor = m_Proto.GetRet().pDtor;
m_BuiltPI->retPassInfo2.pAssignOperator = m_Proto.GetRet().pAssignOperator;
if (m_BuiltPI_Params)
delete m_BuiltPI_Params;
m_BuiltPI_Params = new PassInfo[m_BuiltPI->numOfParams + 1];
if (m_BuiltPI_Params2)
delete m_BuiltPI_Params2;
m_BuiltPI_Params2 = new PassInfo::V2Info[m_BuiltPI->numOfParams + 1];
m_BuiltPI_Params[0].size = 1; // Version 1
m_BuiltPI_Params[0].type = 0;
m_BuiltPI_Params[0].flags = 0;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
m_BuiltPI_Params[i+1].size = m_Proto.GetParam(i).size;
m_BuiltPI_Params[i+1].type = m_Proto.GetParam(i).type;
m_BuiltPI_Params[i+1].flags = m_Proto.GetParam(i).flags;
m_BuiltPI_Params2[i+1].pNormalCtor = m_Proto.GetParam(i).pNormalCtor;
m_BuiltPI_Params2[i+1].pCopyCtor = m_Proto.GetParam(i).pCopyCtor;
m_BuiltPI_Params2[i+1].pDtor = m_Proto.GetParam(i).pDtor;
m_BuiltPI_Params2[i+1].pAssignOperator = m_Proto.GetParam(i).pAssignOperator;
}
m_BuiltPI->paramsPassInfo = m_BuiltPI_Params;
m_BuiltPI->paramsPassInfo2 = m_BuiltPI_Params2;
}
jit_int32_t GenContext::GetRealSize(const IntPassInfo &info)
{
if (info.flags & PassInfo::PassFlag_ByRef)
{
return SIZE_PTR;
}
return static_cast<jit_int32_t>(info.size);
}
// Computes size on the stack
jit_int32_t GenContext::GetStackSize(const IntPassInfo &info)
{
// Align up to 4 byte boundaries
jit_int32_t rs = GetRealSize(info);
if (rs % 4 != 0)
rs = (rs & ~(3)) + 4;
return rs;
}
jit_int8_t GenContext::NextRegEBX_ECX_EDX()
{
switch ((m_RegCounter++) % 3)
{
case 0:
return REG_EBX;
case 1:
return REG_ECX;
case 2:
default:
m_RegCounter = 0;
return REG_EDX;
}
}
jit_int32_t GenContext::PushRef(jit_int32_t param_offset, const IntPassInfo &pi)
{
// push [ebp+<offset>]
IA32_Push_Rm_DispAuto(&m_HookFunc, REG_EBP, param_offset);
return SIZE_PTR;
}
jit_int32_t GenContext::PushBasic(jit_int32_t param_offset, const IntPassInfo &pi)
{
int reg;
int reg2;
switch (pi.size)
{
default:
SH_ASSERT(0, ("Unsupported!"));
return 0;
case 1:
reg = NextRegEBX_ECX_EDX();
//movzx reg, BYTE PTR [ebp+<offset>]
//push reg
IA32_Movzx_Reg32_Rm8_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 2:
reg = NextRegEBX_ECX_EDX();
//movzx reg, WORD PTR [ebp+<offset>]
//push reg
m_HookFunc.write_ubyte(IA32_16BIT_PREFIX);
IA32_Movzx_Reg32_Rm16_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 4:
reg = NextRegEBX_ECX_EDX();
//mov reg, DWORD PTR [ebp+<offset>]
//push reg
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
return 4;
case 8:
reg = NextRegEBX_ECX_EDX();
reg2 = NextRegEBX_ECX_EDX();
//mov reg, DWORD PTR [ebp+<offset>+4]
//mov reg2, DWORD PTR [ebp+<offset>]
//push reg
//push reg2
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg, REG_EBP, param_offset+4);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, reg2, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, reg);
IA32_Push_Reg(&m_HookFunc, reg2);
return 8;
}
}
jit_int32_t GenContext::PushFloat(jit_int32_t param_offset, const IntPassInfo &pi)
{
switch (pi.size)
{
default:
SH_ASSERT(0, ("Unsupported!"));
return 0;
case 4:
//fld DWORD PTR [ebp+<offset>]
//push reg
//fstp DWORD PTR [esp]
IA32_Fld_Mem32_DispAuto(&m_HookFunc, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, NextRegEBX_ECX_EDX());
IA32_Fstp_Mem32_ESP(&m_HookFunc);
return 4;
case 8:
//fld QWORD PTR [ebp+<offset>]
//sub esp, 8
//fstp QWORD PTR [esp]
IA32_Fld_Mem64_DispAuto(&m_HookFunc, REG_EBP, param_offset);
IA32_Sub_Rm_Imm8(&m_HookFunc, REG_ESP, 8, MOD_REG);
IA32_Fstp_Mem64_ESP(&m_HookFunc);
return 8;
}
}
jit_int32_t GenContext::PushObject(jit_int32_t param_offset, const IntPassInfo &pi)
{
// make room on the stack
// sub esp, <size>
IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, GetStackSize(pi), MOD_REG);
// if there is a copy constructor..
if (pi.pCopyCtor)
{
// save eax
// push src addr
// this= target addr = esp+12
// call copy constructor
// restore eax
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_ECX, REG_NOIDX, REG_ESP, NOSCALE, 4);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, param_offset);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EDX, DownCastPtr(pi.pCopyCtor));
IA32_Call_Reg(&m_HookFunc, REG_EDX);
IA32_Pop_Reg(&m_HookFunc, REG_EAX);
}
else
{
jit_uint32_t dwords = DownCastSize(pi.size) / 4;
jit_uint32_t bytes = DownCastSize(pi.size) % 4;
// bitwise copy
//cld
//push edi
//push esi
//lea edi, [esp+8]
//lea esi, [ebp+<offs>]
//if dwords
// mov ecx, <dwords>
// rep movsd
//if bytes
// mov ecx, <bytes>
// rep movsb
//pop esi
//pop edi
IA32_Cld(&m_HookFunc);
IA32_Push_Reg(&m_HookFunc, REG_EDI);
IA32_Push_Reg(&m_HookFunc, REG_ESI);
IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, param_offset);
if (dwords)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, dwords);
IA32_Rep(&m_HookFunc);
IA32_Movsd(&m_HookFunc);
}
if (bytes)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, bytes);
IA32_Rep(&m_HookFunc);
IA32_Movsb(&m_HookFunc);
}
IA32_Pop_Reg(&m_HookFunc, REG_ESI);
IA32_Pop_Reg(&m_HookFunc, REG_EDI);
}
return DownCastSize(pi.size);
}
// May not touch eax!
jit_int32_t GenContext::PushParams(jit_int32_t param_base_offset)
{
jit_int32_t added_to_stack = 0;
jit_int32_t ret = 0;
// compute the offset _after_ the last parameter
jit_int32_t cur_offset = param_base_offset;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
cur_offset += GetStackSize(m_Proto.GetParam(i));
}
// push parameters in reverse order
for (int i = m_Proto.GetNumOfParams() - 1; i >= 0; --i)
{
const IntPassInfo &pi = m_Proto.GetParam(i);
cur_offset -= GetStackSize(pi);
if (pi.flags & PassInfo::PassFlag_ByVal)
{
switch (pi.type)
{
case PassInfo::PassType_Basic:
ret = PushBasic(cur_offset, pi);
break;
case PassInfo::PassType_Float:
ret = PushFloat(cur_offset, pi);
break;
case PassInfo::PassType_Object:
ret = PushObject(cur_offset, pi);
break;
}
}
else if (pi.flags & PassInfo::PassFlag_ByRef)
{
PushRef(cur_offset, pi);
}
else
{
SH_ASSERT(0, ("Unsupported!"));
}
added_to_stack += ret;
}
return added_to_stack;
}
void GenContext::SaveRetVal(int v_where)
{
// :TODO: assign op support
// :TODO: memory return support
size_t size = m_Proto.GetRet().size;
if (size == 0)
{
// No return value -> nothing
return;
}
if (m_Proto.GetRet().type == PassInfo::PassType_Float)
{
if (size == 4)
IA32_Fstp_Mem32_DispAuto(&m_HookFunc, REG_EBP, v_where);
else if (size == 8)
IA32_Fstp_Mem64_DispAuto(&m_HookFunc, REG_EBP, v_where);
}
else if (m_Proto.GetRet().type == PassInfo::PassType_Basic)
{
if (size <= 4)
{
// size <= 4: return in EAX
// We align <4 sizes up to 4
// mov [ebp + v_plugin_ret], eax
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
}
else if (size <= 8)
{
// size <= 4: return in EAX:EDX
// We align 4<x<8 sizes up to 8
// mov [ebp + v_plugin_ret], eax
// mov [ebp + v_plugin_ret + 4], edx
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_where);
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EDX, v_where + 4);
}
else
{
// size >8: return in memory
// :TODO:
// add flag: MSVC_RetInMemory?
}
}
// :TODO: object
}
void GenContext::ProcessPluginRetVal(int v_cur_res, int v_pContext, int v_plugin_ret)
{
// only for non-void functions!
if (m_Proto.GetRet().size == 0)
return;
// if (cur_res >= MRES_OVERRIDE)
// *reinterpret_cast<my_rettype*>(pContext->GetOverrideRetPtr()) = plugin_ret;
// eax = cur_res
// cmp eax,MRES_OVERRIDE
// jnge thelabel
// pContext->GetOverrideRetPtr() --> overrideretptr in eax
// *eax = plugin_ret
// thelabel:
//
jitoffs_t tmppos, counter;
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Cmp_Rm_Imm32(&m_HookFunc, MOD_REG, REG_EAX, MRES_OVERRIDE);
tmppos = IA32_Jump_Cond_Imm8(&m_HookFunc, CC_NGE, 0);
m_HookFunc.start_count(counter);
// eax = pContext->GetOverrideRetPtr()
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax + 4]
// call eax
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
// vtbloffs=0, vtblidx=1
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EAX, 4);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// *eax = plugin_ret
if (m_Proto.GetRet().pAssignOperator)
{
// lea edx, [ebp + v_plugin_ret]
// msvc: ecx = eax <-- dest addr
// gcc: push eax <-- dest addr
// push edx <-- src addr
// call it
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_plugin_ret);
#if SH_COMP == SH_COMP_MSVC
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ECX, REG_EAX, MOD_REG);
#elif SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_EAX);
#endif
IA32_Push_Reg(&m_HookFunc, REG_EDX);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
}
else
{
jit_uint32_t dwords = DownCastSize(m_Proto.GetRet().size) / 4;
jit_uint32_t bytes = DownCastSize(m_Proto.GetRet().size) % 4;
// bitwise copy
//cld
//push edi
//push esi
//mov edi, eax <-- destination
//lea esi, [ebp+v_plugin_ret] <-- src
//if dwords
// mov ecx, <dwords>
// rep movsd
//if bytes
// mov ecx, <bytes>
// rep movsb
//pop esi
//pop edi
IA32_Cld(&m_HookFunc);
IA32_Push_Reg(&m_HookFunc, REG_EDI);
IA32_Push_Reg(&m_HookFunc, REG_ESI);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDI, REG_EAX, MOD_REG);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_plugin_ret);
if (dwords)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, dwords);
IA32_Rep(&m_HookFunc);
IA32_Movsd(&m_HookFunc);
}
if (bytes)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, bytes);
IA32_Rep(&m_HookFunc);
IA32_Movsb(&m_HookFunc);
}
IA32_Pop_Reg(&m_HookFunc, REG_ESI);
IA32_Pop_Reg(&m_HookFunc, REG_EDI);
}
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
}
void GenContext::PrepareReturn(int v_status, int v_pContext, int v_retptr)
{
// only for non-void functions!
if (m_Proto.GetRet().size == 0)
return;
// retptr = status >= MRES_OVERRIDE ? pContext->GetOverrideRetPtr() : pContext->GetOrigRetPtr()
// OverrideRetPtr: vtblidx = 1
// OrigRetPtr: vtbldix = 2
// vtblidx = (status >= MRES_OVERRIDE) ? 1 : 2
//
// eax = pContext->GetOverrideRetPtr()
// ECX = pContext
// gcc: push ecx
// eax = (status < MRES_OVERRIDE) ? 1 : 0
// xor eax, eax
// cmp [ebp + v_status], MRES_OVERRIDE
// setl al <-- setcc optimization for ternary operators,
// lea eax, [4*eax + 0x4]
// edx = [ecx]
// add edx, eax
// mov edx, [edx]
// call edx
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
IA32_Xor_Reg_Rm(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
IA32_Cmp_Rm_Disp8_Imm8(&m_HookFunc, REG_EBP, v_status, MRES_OVERRIDE);
IA32_SetCC_Rm8(&m_HookFunc, REG_EAX, CC_L);
IA32_Lea_Reg_RegMultImm32(&m_HookFunc, REG_EAX, REG_EAX, SCALE4, 4);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
IA32_Add_Reg_Rm(&m_HookFunc, REG_EDX, REG_EAX, MOD_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EDX, REG_EDX, MOD_MEM_REG);
IA32_Call_Reg(&m_HookFunc, REG_EDX);
IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_EAX, v_retptr);
}
void GenContext::DoReturn(int v_retptr)
{
size_t size = m_Proto.GetRet().size;
if (!size)
return;
// :TODO: assign op support
// :TODO: memory return support
// Get real ret pointer into ecx
// mov ecx, [ebp + v_ret_ptr]
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_retptr);
if (m_Proto.GetRet().type == PassInfo::PassType_Float)
{
if (size == 4)
IA32_Fld_Mem32(&m_HookFunc, REG_ECX);
else if (size == 8)
IA32_Fld_Mem64(&m_HookFunc, REG_ECX);
}
else if (m_Proto.GetRet().type == PassInfo::PassType_Basic)
{
if (size <= 4)
{
// size <= 4: return in EAX
// We align <4 sizes up to 4
// mov eax, [ecx]
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
}
else if (size <= 8)
{
// size <= 4: return in EAX:EDX
// We align 4<x<8 sizes up to 8
// mov eax, [ecx]
// mov edx, [ecx+4]
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_ECX, 4);
}
else
{
// size >8: return in memory
// :TODO:
// add flag: MSVC_RetInMemory?
}
}
// :TODO: object
}
void GenContext::GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter,
int v_pContext, int base_param_offset, int v_plugin_ret)
{
jitoffs_t counter, tmppos;
jitoffs_t counter2, tmppos2;
jitoffs_t loop_begin_counter;
// prev_res = MRES_IGNORED
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_prev_res);
m_HookFunc.start_count(loop_begin_counter);
// eax = pContext->GetNext()
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax]
// call eax
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
// vtbloffs=0, vtblidx=0
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_EAX, MOD_MEM_REG);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// quit on zero
// test eax, eax
// jz exit
IA32_Test_Rm_Reg(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_Z, 0);
m_HookFunc.start_count(counter);
// prev_res = MRES_IGNORED
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_cur_res);
// iter->call()
// push params
// ecx = eax
// gcc: push ecx
// eax = [ecx]
// eax = [eax+2*SIZE_PTR]
// call eax
jit_int32_t gcc_clean_bytes = PushParams(base_param_offset);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ECX, REG_EAX, MOD_REG);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EAX, 2*SIZE_PTR);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
SaveRetVal(v_plugin_ret);
// cleanup
#if SH_COMP == SH_COMP_GCC
// params + thisptr
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG);
#endif
// process meta return:
// prev_res = cur_res
// if (cur_res > status) status = cur_res;
//
// eax = cur_res
// edx = status
// prev_res = eax
// cmp eax,edx
// jng thelabel
// status = eax
// thelabel:
//
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EDX, REG_EBP, v_status);
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_prev_res);
IA32_Cmp_Reg_Rm(&m_HookFunc, REG_EAX, REG_EDX, MOD_REG);
tmppos2 = IA32_Jump_Cond_Imm8(&m_HookFunc, CC_NG, 0);
m_HookFunc.start_count(counter2);
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_status);
m_HookFunc.end_count(counter2);
m_HookFunc.rewrite(tmppos2, static_cast<jit_uint8_t>(counter2));
// process retval for non-void functions
ProcessPluginRetVal(v_cur_res, v_pContext, v_plugin_ret);
// jump back to loop begin
tmppos2 = IA32_Jump_Imm32(&m_HookFunc, 0);
m_HookFunc.end_count(loop_begin_counter);
m_HookFunc.rewrite(tmppos2, -static_cast<jit_int32_t>(loop_begin_counter));
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_int32_t>(counter));
}
short GenContext::GetParamsStackSize()
{
short acc = 0;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
acc += GetStackSize(m_Proto.GetParam(i));
}
return acc;
}
void GenContext::GenerateCallOrig(int v_status, int v_pContext,
int param_base_offs, int v_this, int v_vfnptr_origentry, int v_orig_ret, int v_override_ret)
{
jitoffs_t counter, tmppos;
jitoffs_t counter2, tmppos2;
jitoffs_t counter3, tmppos3;
// if (status != MRES_SUPERCEDE && pConteext->ShouldCallOrig())
// *v_orig_ret = orig_call()
// else
// *v_orig_ret = *v_override_ret
// mov eax, status
// cmp eax, MRES_SUPERCEDE
// je dont_call
// call pContext->ShouldCallOrig()
// test al, al !! important: al, not eax! bool is only stored in the LSbyte
// jz dont_call
//
// orig_call()
// SaveRet(v_orig_ret)
// jmp skip_dont_call:
//
// dont_call:
// *v_orig_ret = *v_override_ret
// skip_dont_call:
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_status);
IA32_Cmp_Rm_Imm32(&m_HookFunc, MOD_REG, REG_EAX, MRES_SUPERCEDE);
tmppos = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_E, 0);
m_HookFunc.start_count(counter);
// eax = pContext->ShouldCallOrig()
// ECX = pContext
// gcc: push ecx
// eax = [ecx]
// eax = [eax + 3*PTR_SIZE]
// call eax
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_pContext);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
// vtbloffs=0, vtblidx=3
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_ECX, MOD_MEM_REG);
IA32_Mov_Reg_Rm_Disp8(&m_HookFunc, REG_EAX, REG_EAX, 3*SIZE_PTR);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
IA32_Test_Rm_Reg8(&m_HookFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos2 = IA32_Jump_Cond_Imm32(&m_HookFunc, CC_Z, 0);
m_HookFunc.start_count(counter2);
// push params
jit_int32_t gcc_clean_bytes = PushParams(param_base_offs);
// thisptr
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_this);
#if SH_COMP == SH_COMP_GCC
// on gcc/mingw, this is the first parameter
IA32_Push_Reg(&m_HookFunc, REG_ECX);
// on msvc, simply leave it in ecx
#endif
// call
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_vfnptr_origentry);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// cleanup
#if SH_COMP == SH_COMP_GCC
// params + thisptr
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG);
#endif
// save retval
SaveRetVal(v_orig_ret);
// Skip don't call variant
tmppos3 = IA32_Jump_Imm32(&m_HookFunc, 0);
m_HookFunc.start_count(counter3);
// don't call:
m_HookFunc.end_count(counter);
m_HookFunc.rewrite(tmppos, static_cast<jit_uint32_t>(counter));
m_HookFunc.end_count(counter2);
m_HookFunc.rewrite(tmppos2, static_cast<jit_uint32_t>(counter2));
// *v_orig_ret = *v_override_ret
if (m_Proto.GetRet().pAssignOperator)
{
// lea edx, [ebp + v_override_ret] <-- src addr
// lea ecx, [ebp + v_orig_ret] <-- dest addr
// gcc: push ecx
// push edx <-- src addr
// call it
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_override_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#endif
IA32_Push_Reg(&m_HookFunc, REG_EDX);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
}
else
{
jit_uint32_t dwords = DownCastSize(m_Proto.GetRet().size) / 4;
jit_uint32_t bytes = DownCastSize(m_Proto.GetRet().size) % 4;
// bitwise copy
//cld
//push edi
//push esi
//lea edi, [ebp+v_orig_ret] <-- destination
//lea esi, [ebp+v_override_ret] <-- src
//if dwords
// mov ecx, <dwords>
// rep movsd
//if bytes
// mov ecx, <bytes>
// rep movsb
//pop esi
//pop edi
IA32_Cld(&m_HookFunc);
IA32_Push_Reg(&m_HookFunc, REG_EDI);
IA32_Push_Reg(&m_HookFunc, REG_ESI);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_orig_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_override_ret);
if (dwords)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, dwords);
IA32_Rep(&m_HookFunc);
IA32_Movsd(&m_HookFunc);
}
if (bytes)
{
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, bytes);
IA32_Rep(&m_HookFunc);
IA32_Movsb(&m_HookFunc);
}
IA32_Pop_Reg(&m_HookFunc, REG_ESI);
IA32_Pop_Reg(&m_HookFunc, REG_EDI);
}
// skip don't call label target:
m_HookFunc.end_count(counter3);
m_HookFunc.rewrite(tmppos3, static_cast<jit_uint32_t>(counter3));
}
// Sets *v_pContext to return value
void GenContext::CallSetupHookLoop(int v_orig_ret, int v_override_ret,
int v_cur_res, int v_prev_res, int v_status, int v_vfnptr_origentry,
int v_this, int v_pContext)
{
// call shptr->SetupHookLoop(ms_HI, ourvfnptr, reinterpret_cast<void*>(this),
// &vfnptr_origentry, &status, &prev_res, &cur_res, &orig_ret, &override_ret);
// The last two params are null for void funcs.
if (m_Proto.GetRet().size == 0)
{
// void
IA32_Push_Imm8(&m_HookFunc, 0); // orig_ret
IA32_Push_Imm8(&m_HookFunc, 0); // override_ret
}
else
{
// orig_ret and override_ret
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, v_override_ret);
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_orig_ret);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
}
// cur_res and prev_res
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EAX, REG_EBP, v_cur_res);
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EDX, REG_EBP, v_prev_res);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
// status and vfnptr_origentry
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EAX, REG_EBP, v_status);
IA32_Lea_DispRegImm8(&m_HookFunc, REG_EDX, REG_EBP, v_vfnptr_origentry);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
IA32_Push_Reg(&m_HookFunc, REG_EDX);
// this
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_this);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// our vfn ptr
// *(this + vtbloffs) + SIZE_PTR*vtblidx
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_this); // get this into ecx (gcc!)
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_ECX, m_VtblOffs);
IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_EAX, m_VtblIdx * SIZE_PTR, MOD_REG);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// *m_pHI
IA32_Mov_Rm_Imm32(&m_HookFunc, REG_EDX, DownCastPtr(m_pHI), MOD_REG);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EAX, REG_EDX, MOD_MEM_REG);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// set up thisptr
#if SH_COMP == SH_COMP_GCC
// on gcc/mingw, this is the first parameter
IA32_Push_Imm32(&m_HookFunc, DownCastPtr(m_SHPtr));
#elif SH_COMP == SH_COMP_MSVC
// on msvc, it's ecx
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, DownCastPtr(m_SHPtr));
#endif
// call the function. vtbloffs = 0, vtblidx = 19
// get vtptr into edx -- we know shptr on jit time -> dereference it here!
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX,
(*reinterpret_cast<jit_uint32_t**>(m_SHPtr))[19]);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
#if SH_COMP == SH_COMP_GCC
// 9 params + hidden thisptr param
IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 10*SIZE_PTR, MOD_REG);
#endif
// store return value
IA32_Mov_Rm_Reg_Disp8(&m_HookFunc, REG_EBP, REG_EAX, v_pContext);
}
void GenContext::CallEndContext(int v_pContext)
{
// call endcontext:
// shptr->EndContext(pContex)
IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EBP, v_pContext);
IA32_Push_Reg(&m_HookFunc, REG_EAX);
// thisptr
#if SH_COMP == SH_COMP_GCC
// on gcc/mingw, this is the first parameter
IA32_Push_Imm32(&m_HookFunc, DownCastPtr(m_SHPtr));
#elif SH_COMP == SH_COMP_MSVC
// on msvc, it's ecx
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_ECX, DownCastPtr(m_SHPtr));
#endif
// get vtptr into edx -- we know shptr on jit time -> dereference it here!
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX,
(*reinterpret_cast<jit_uint32_t**>(m_SHPtr))[20]);
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
#if SH_COMP == SH_COMP_GCC
// 1 param + hidden thisptr param
IA32_Add_Rm_Imm8(&m_HookFunc, REG_ESP, 2*SIZE_PTR, MOD_REG);
#endif
}
unsigned char * GenContext::GenerateHookFunc()
{
// prologue
IA32_Push_Reg(&m_HookFunc, REG_EBP);
IA32_Push_Reg(&m_HookFunc, REG_EBX);
IA32_Mov_Reg_Rm(&m_HookFunc, REG_EBP, REG_ESP, MOD_REG);
// on msvc, save thisptr
#if SH_COMP == SH_COMP_MSVC
const jit_int8_t v_this = -4;
const int addstackoffset = -4;
IA32_Push_Reg(&m_HookFunc, REG_ECX);
#elif SH_COMP == SH_COMP_GCC
const jit_int8_t v_this = 8; // first param
const int addstackoffset = 0;
#endif
// ********************** stack frame **********************
// MSVC
// second param (gcc: first real param) ebp + 16
// first param (gcc: thisptr) ebp + 12
// ret address: ebp + 8
// caller's ebp ebp + 4
// saved ebx ebp
// MSVC ONLY: current this ebp - 4
// void *vfnptr_origentry ebp - 4 -4
// META_RES status = MRES_IGNORED ebp - 8 -4
// META_RES prev_res ebp - 12 -4
// META_RES cur_res ebp - 16 -4
// IMyDelegate *iter ebp - 20 -4
// IHookContext *pContext ebp - 24 -4
// == 3 ptrs + 3 enums = 24 bytes
//
// non-void: add:
// my_rettype *ret_ptr ebp - 28 -4
// my_rettype orig_ret ebp - 28 - sizeof(my_rettype) -4
// my_rettype override_ret ebp - 28 - sizeof(my_rettype)*2 -4
// my_rettype plugin_ret ebp - 28 - sizeof(my_rettype)*3 -4
// == + 3 * sizeof(my_rettype) bytes
const jit_int8_t v_vfnptr_origentry = -4 + addstackoffset;
const jit_int8_t v_status = -8 + addstackoffset;
const jit_int8_t v_prev_res = -12 + addstackoffset;
const jit_int8_t v_cur_res = -16 + addstackoffset;
const jit_int8_t v_iter = -20 + addstackoffset;
const jit_int8_t v_pContext = -24 + addstackoffset;
#if SH_COMP == SH_COMP_GCC
const jit_int32_t param_base_offs = 16;
#elif SH_COMP == SH_COMP_MSVC
const jit_int32_t param_base_offs = 12;
#endif
jit_int32_t v_ret_ptr = -28 + addstackoffset;
jit_int32_t v_orig_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 1;
jit_int32_t v_override_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 2;
jit_int32_t v_plugin_ret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 3;
// Hash for temporary storage for byval params with copy constructors
// (param, offset into stack)
short usedStackBytes = 3*SIZE_MWORD + 3*SIZE_PTR + // vfnptr_origentry, status, prev_res, cur_res, iter, pContext
3 * GetStackSize(m_Proto.GetRet()) + (m_Proto.GetRet().size == 0 ? 0 : SIZE_PTR) // ret_ptr, orig_ret, override_ret, plugin_ret
- addstackoffset; // msvc: current thisptr
IA32_Sub_Rm_Imm32(&m_HookFunc, REG_ESP, usedStackBytes, MOD_REG);
// init status localvar
IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_status);
// Call constructors for ret vars if required
if(m_Proto.GetRet().pNormalCtor)
{
// :TODO: Gcc version
// orig_reg
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// override_reg
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
// plugin_ret
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_plugin_ret);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pNormalCtor));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
}
// ********************** SetupHookLoop **********************
CallSetupHookLoop(v_orig_ret, v_override_ret, v_cur_res, v_prev_res, v_status, v_vfnptr_origentry,
v_this, v_pContext);
// ********************** call pre hooks **********************
GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs,
v_plugin_ret);
// ********************** call orig func **********************
GenerateCallOrig(v_status, v_pContext, param_base_offs, v_this, v_vfnptr_origentry, v_orig_ret,
v_override_ret);
// ********************** call post hooks **********************
GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs,
v_plugin_ret);
// ********************** end context and return **********************
PrepareReturn(v_status, v_pContext, v_ret_ptr);
CallEndContext(v_pContext);
// Call destructors of byval object params which have a destructor
jit_int32_t cur_param_pos = param_base_offs;
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
const IntPassInfo &pi = m_Proto.GetParam(i);
if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) &&
(pi.flags & PassInfo::PassFlag_ByVal))
{
IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, cur_param_pos);
IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor));
IA32_Call_Reg(&m_HookFunc, REG_EAX);
}
cur_param_pos += GetStackSize(pi);
}
DoReturn(v_ret_ptr);
// !! :TODO: Call destructors of orig_ret/ ...
// epilogue
IA32_Mov_Reg_Rm(&m_HookFunc, REG_ESP, REG_EBP, MOD_REG);
IA32_Pop_Reg(&m_HookFunc, REG_EBX);
IA32_Pop_Reg(&m_HookFunc, REG_EBP);
IA32_Return_Popstack(&m_HookFunc, GetParamsStackSize());
// Store pointer for later use
// m_HookfuncVfnPtr is a pointer to a void* because SH expects a pointer
// into the hookman's vtable
*m_HookfuncVfnptr = reinterpret_cast<void*>(m_HookFunc.GetData());
return m_HookFunc.GetData();
}
// Pre-condition: GenerateHookFunc() has been called!
unsigned char * GenContext::GeneratePubFunc()
{
jitoffs_t counter, tmppos;
// The pubfunc is a static cdecl function.
// C Code:
// int HookManPubFunc(
// bool store, ebp + 8
// IHookManagerInfo *hi ebp + 12
// )
// {
// if (store)
// *m_pHI = hi;
// if (hi)
// hi->SetInfo(HOOKMAN_VERSION, m_VtblOffs, m_VtblIdx, m_Proto.GetProto(), m_HookfuncVfnptr)
// }
// prologue
IA32_Push_Reg(&m_PubFunc, REG_EBP);
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EBP, REG_ESP, MOD_REG);
// save store in eax, hi in ecx
IA32_Movzx_Reg32_Rm8_Disp8(&m_PubFunc, REG_EAX, REG_EBP, 8);
IA32_Mov_Reg_Rm_DispAuto(&m_PubFunc, REG_ECX, REG_EBP, 12);
// Check for store == 0
IA32_Test_Rm_Reg8(&m_PubFunc, REG_EAX, REG_EAX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm8(&m_PubFunc, CC_Z, 0);
m_PubFunc.start_count(counter);
// nonzero -> store hi
IA32_Mov_Rm_Imm32(&m_PubFunc, REG_EDX, DownCastPtr(m_pHI), MOD_REG);
IA32_Mov_Rm_Reg(&m_PubFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
// zero
m_PubFunc.end_count(counter);
m_PubFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
// check for hi == 0
IA32_Test_Rm_Reg(&m_PubFunc, REG_ECX, REG_ECX, MOD_REG);
tmppos = IA32_Jump_Cond_Imm8(&m_PubFunc, CC_Z, 0);
m_PubFunc.start_count(counter);
// nonzero -> call vfunc
// push params in reverse order
IA32_Push_Imm32(&m_PubFunc, DownCastPtr(m_HookfuncVfnptr));
IA32_Push_Imm32(&m_PubFunc, DownCastPtr(m_BuiltPI));
IA32_Push_Imm32(&m_PubFunc, m_VtblIdx);
IA32_Push_Imm32(&m_PubFunc, m_VtblOffs);
IA32_Push_Imm32(&m_PubFunc, SH_HOOKMAN_VERSION);
// hi == this is in ecx
// on gcc/mingw, ecx is the first parameter
#if SH_COMP == SH_COMP_GCC
IA32_Push_Reg(&m_PubFunc, REG_ECX);
#endif
// call the function. vtbloffs = 0, vtblidx = 0
// get vtptr into edx
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EDX, REG_ECX, MOD_MEM_REG);
// get funcptr into eax
IA32_Mov_Reg_Rm(&m_PubFunc, REG_EAX, REG_EDX, MOD_MEM_REG);
IA32_Call_Reg(&m_PubFunc, REG_EAX);
// on gcc/mingw, we have to clean up after the call
#if SH_COMP == SH_COMP_GCC
// 5 params + hidden thisptr param
IA32_Add_Rm_Imm8(&m_PubFunc, REG_ESP, 6*SIZE_MWORD, MOD_REG);
#endif
// zero
m_PubFunc.end_count(counter);
m_PubFunc.rewrite(tmppos, static_cast<jit_uint8_t>(counter));
// return value
IA32_Xor_Reg_Rm(&m_PubFunc, REG_EAX, REG_EAX, MOD_REG);
// epilogue
IA32_Mov_Reg_Rm(&m_PubFunc, REG_ESP, REG_EBP, MOD_REG);
IA32_Pop_Reg(&m_PubFunc, REG_EBP);
IA32_Return(&m_PubFunc);
SetMemAccess(reinterpret_cast<void*>(m_PubFunc.GetData()), m_PubFunc.GetSize(),
SH_MEM_READ | SH_MEM_EXEC);
return m_PubFunc;
}
bool GenContext::PassInfoSupported(const IntPassInfo &pi, bool is_ret)
{
if (pi.type != PassInfo::PassType_Basic &&
pi.type != PassInfo::PassType_Float &&
pi.type != PassInfo::PassType_Object)
{
return false;
}
if (pi.type == PassInfo::PassType_Object &&
(pi.flags & PassInfo::PassFlag_ByVal))
{
if ((pi.flags & PassInfo::PassFlag_CCtor) && !pi.pNormalCtor)
return false;
if ((pi.flags & PassInfo::PassFlag_ODtor) && !pi.pDtor)
return false;
// only care for assignop and normalctor for return types
if (is_ret && (pi.flags & PassInfo::PassFlag_AssignOp) && !pi.pAssignOperator)
return false;
if (is_ret && (pi.flags & PassInfo::PassFlag_CCtor) && !pi.pNormalCtor)
return false;
}
if ((pi.flags & (PassInfo::PassFlag_ByVal | PassInfo::PassFlag_ByRef)) == 0)
{
return false; // Neither byval nor byref!
}
return true;
}
HookManagerPubFunc GenContext::Generate()
{
Clear();
// Check conditions:
// -1) good proto version
// 0) we don't support unknown passtypes, convention, ...
// 1) we don't support functions which return objects by value or take parameters by value
// that have a constructor, a destructor or an overloaded assignment op
// (we wouldn't know how to call it!)
if (m_Proto.GetVersion() < 1)
{
return NULL;
}
if (m_Proto.GetConvention() != ProtoInfo::CallConv_Cdecl &&
m_Proto.GetConvention() != ProtoInfo::CallConv_ThisCall)
{
return NULL;
}
if (m_Proto.GetRet().size != 0 && !PassInfoSupported(m_Proto.GetRet(), true))
{
return NULL;
}
for (int i = 0; i < m_Proto.GetNumOfParams(); ++i)
{
if (!PassInfoSupported(m_Proto.GetParam(i), false))
return NULL;
}
BuildProtoInfo();
GenerateHookFunc();
return reinterpret_cast<HookManagerPubFunc>(GeneratePubFunc());
}
}
}

View File

@ -0,0 +1,232 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
*
* Author(s): Pavol "PM OnoTo" Marko
* ============================
*/
#ifndef __SOURCEHOOK_HOOKMANGEN_H__
#define __SOURCEHOOK_HOOKMANGEN_H__
#include "sourcehook_impl.h"
#include "windows.h"
namespace SourceHook
{
namespace Impl
{
// Code gen stuff
#if defined HAVE_STDINT_H && !defined WIN32
#include <stdint.h>
typedef int8_t jit_int8_t;
typedef uint8_t jit_uint8_t;
typedef int32_t jit_int32_t;
typedef uint32_t jit_uint32_t;
typedef int64_t jit_int64_t;
typedef uint64_t jit_uint64_t;
#elif defined WIN32
typedef __int8 jit_int8_t;
typedef unsigned __int8 jit_uint8_t;
typedef __int32 jit_int32_t;
typedef unsigned __int32 jit_uint32_t;
typedef __int64 jit_int64_t;
typedef unsigned __int64 jit_uint64_t;
#endif
typedef unsigned int jitoffs_t;
typedef signed int jitrel_t;
class GenBuffer
{
unsigned char *m_pData;
jitoffs_t m_Size;
jitoffs_t m_AllocatedSize;
public:
GenBuffer() : m_pData(NULL), m_Size(0), m_AllocatedSize(0)
{
}
~GenBuffer()
{
clear();
}
jitoffs_t GetSize()
{
return m_Size;
}
unsigned char *GetData()
{
return m_pData;
}
template <class PT> void push(PT what)
{
push((const unsigned char *)&what, sizeof(PT));
}
void push(const unsigned char *data, jitoffs_t size)
{
jitoffs_t newSize = m_Size + size;
if (newSize > m_AllocatedSize)
{
m_AllocatedSize = newSize > m_AllocatedSize*2 ? newSize : m_AllocatedSize*2;
if (m_AllocatedSize < 64)
m_AllocatedSize = 64;
unsigned char *newBuf;
try
{
//!!!! Better use of pages! or something!
newBuf = reinterpret_cast<unsigned char*>(VirtualAlloc(NULL, m_AllocatedSize, MEM_COMMIT, PAGE_READWRITE));
}
catch (std::bad_alloc)
{
newBuf = NULL;
}
if (!newBuf)
{
SH_ASSERT(0, ("bad_alloc: couldn't allocate 0x%08X bytes of memory\n", m_AllocatedSize));
return;
}
memcpy((void*)newBuf, (const void*)m_pData, m_Size);
if (m_pData)
VirtualFree(m_pData, 0, MEM_RELEASE);
m_pData = newBuf;
}
memcpy((void*)(m_pData + m_Size), (const void*)data, size);
m_Size = newSize;
}
template <class PT> void rewrite(jitoffs_t offset, PT what)
{
rewrite(offset, (const unsigned char *)&what, sizeof(PT));
}
void rewrite(jitoffs_t offset, const unsigned char *data, jitoffs_t size)
{
SH_ASSERT(offset + size <= m_AllocatedSize, ("rewrite too far"));
memcpy((void*)(m_pData + offset), (const void*)data, size);
}
void clear()
{
if (m_pData)
VirtualFree(m_pData, 0, MEM_RELEASE);
m_pData = NULL;
m_Size = 0;
m_AllocatedSize = 0;
}
operator unsigned char *()
{
return GetData();
}
void write_ubyte(jit_uint8_t x) { push(x); }
void write_byte(jit_uint8_t x) { push(x); }
void write_ushort(unsigned short x) { push(x); }
void write_short(signed short x) { push(x); }
void write_uint32(jit_uint32_t x) { push(x); }
void write_int32(jit_uint32_t x) { push(x); }
jitoffs_t get_outputpos()
{
return m_Size;
}
void start_count(jitoffs_t &offs)
{
offs = get_outputpos();
}
void end_count(jitoffs_t &offs)
{
offs = get_outputpos() - offs;
}
// :TODO: real buffer which uses virtualalloc correctly
};
class GenContext
{
const static int SIZE_MWORD = 4;
const static int SIZE_PTR = sizeof(void*);
CProto m_Proto;
int m_VtblOffs;
int m_VtblIdx;
ISourceHook *m_SHPtr;
GenBuffer m_HookFunc;
GenBuffer m_PubFunc;
ProtoInfo *m_BuiltPI;
PassInfo *m_BuiltPI_Params;
PassInfo::V2Info *m_BuiltPI_Params2;
// For hookfunc
void **m_pHI;
void **m_HookfuncVfnptr;
// Level 3 - Helpers
int m_RegCounter;
jit_int8_t NextRegEBX_ECX_EDX();
// size info
jit_int32_t GetRealSize(const IntPassInfo &info);
jit_int32_t GetStackSize(const IntPassInfo &info);
short GetParamsStackSize(); // sum(GetStackSize(i), 0 <= i < numOfParams)
// Param push
jit_int32_t PushParams(jit_int32_t param_base_offset);
jit_int32_t PushRef(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushBasic(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushFloat(jit_int32_t param_offset, const IntPassInfo &pi);
jit_int32_t PushObject(jit_int32_t param_offset, const IntPassInfo &pi);
// Ret val processing
void SaveRetVal(int v_where);
void ProcessPluginRetVal(int v_cur_res, int v_pContext, int v_plugin_ret);
void PrepareReturn(int v_status, int v_pContext, int v_retptr);
void DoReturn(int v_retptr);
// Call hooks
void GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter,
int v_pContext, int base_param_offset, int v_plugin_ret);
// Call orig
void GenerateCallOrig(int v_status, int v_pContext,
int param_base_offs, int v_this, int v_vfnptr_origentry, int v_orig_ret, int v_override_ret);
// Hook loop
void CallSetupHookLoop(int v_orig_ret, int v_override_ret,
int v_cur_res, int v_prev_res, int v_status, int v_vnfptr_origentry,
int v_this, int v_pContext);
void CallEndContext(int v_pContext);
// Level 2 -> called from Generate()
bool PassInfoSupported(const IntPassInfo &pi, bool is_ret);
void Clear();
void BuildProtoInfo();
unsigned char *GenerateHookFunc();
unsigned char *GeneratePubFunc();
public:
// Level 1 -> Public interface
GenContext(const ProtoInfo *proto, int vtbl_offs, int vtbl_idx, ISourceHook *pSHPtr);
~GenContext();
HookManagerPubFunc Generate();
};
}
}
#endif

View File

@ -0,0 +1,1585 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourcePawn JIT SDK
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
*/
#ifndef __SOURCEHOOK_HOOKMANGEN_X86_H__
#define __SOURCEHOOK_HOOKMANGEN_X86_H__
#include <limits.h>
//MOD R/M
#define MOD_MEM_REG 0
#define MOD_DISP8 1
#define MOD_DISP32 2
#define MOD_REG 3
//SIB
#define NOSCALE 0
#define SCALE2 1
#define SCALE4 2
#define SCALE8 3
//Register codes
#define REG_EAX 0
#define REG_ECX 1
#define REG_EDX 2
#define REG_EBX 3
#define REG_ESP 4
#define REG_SIB 4
#define REG_NOIDX 4
#define REG_IMM_BASE 5
#define REG_EBP 5
#define REG_ESI 6
#define REG_EDI 7
#define IA32_16BIT_PREFIX 0x66
//condition codes (for example, Jcc opcodes)
#define CC_B 0x2
#define CC_NAE CC_B
#define CC_NB 0x3
#define CC_AE CC_NB
#define CC_E 0x4
#define CC_Z CC_E
#define CC_NE 0x5
#define CC_NZ CC_NE
#define CC_NA 0x6
#define CC_BE CC_NA
#define CC_A 0x7
#define CC_NBE CC_A
#define CC_L 0xC
#define CC_NGE CC_L
#define CC_NL 0xD
#define CC_GE CC_NL
#define CC_NG 0xE
#define CC_LE CC_NG
#define CC_G 0xF
#define CC_NLE CC_G
//Opcodes with encoding information
#define IA32_XOR_RM_REG 0x31 // encoding is /r
#define IA32_XOR_REG_RM 0x33 // encoding is /r
#define IA32_XOR_EAX_IMM32 0x35 // encoding is /r
#define IA32_XOR_RM_IMM32 0x81 // encoding is /6
#define IA32_XOR_RM_IMM8 0x83 // encoding is /6
#define IA32_ADD_RM_REG 0x01 // encoding is /r
#define IA32_ADD_REG_RM 0x03 // encoding is /r
#define IA32_ADD_RM_IMM32 0x81 // encoding is /0
#define IA32_ADD_RM_IMM8 0x83 // encoding is /0
#define IA32_ADD_EAX_IMM32 0x05 // no extra encoding
#define IA32_SUB_RM_REG 0x29 // encoding is /r
#define IA32_SUB_REG_RM 0x2B // encoding is /r
#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 <imm8>
#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 <imm32>
#define IA32_SBB_REG_RM 0x1B // encoding is /r
#define IA32_SBB_RM_IMM8 0x83 // encoding is <imm32>
#define IA32_JMP_IMM32 0xE9 // encoding is imm32
#define IA32_JMP_IMM8 0xEB // encoding is imm8
#define IA32_JMP_RM 0xFF // encoding is /4
#define IA32_CALL_IMM32 0xE8 // relative call, <imm32>
#define IA32_CALL_RM 0xFF // encoding is /2
#define IA32_MOV_REG_IMM 0xB8 // encoding is +r <imm32>
#define IA32_MOV_RM8_REG 0x88 // encoding is /r
#define IA32_MOV_RM_REG 0x89 // encoding is /r
#define IA32_MOV_REG_RM 0x8B // encoding is /r
#define IA32_MOV_REG8_RM8 0x8A // encoding is /r
#define IA32_MOV_RM8_REG8 0x88 // encoding is /r
#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0
#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 <imm32>
#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 <imm8>
#define IA32_CMP_AL_IMM32 0x3C // no extra encoding
#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding
#define IA32_CMP_RM_REG 0x39 // encoding is /r
#define IA32_CMP_REG_RM 0x3B // encoding is /r
#define IA32_CMPSB 0xA6 // no extra encoding
#define IA32_TEST_RM_REG8 0x84 // encoding is /r
#define IA32_TEST_RM_REG 0x85 // encoding is /r
#define IA32_JCC_IMM 0x70 // encoding is +cc <imm8>
#define IA32_JCC_IMM32_1 0x0F // opcode part 1
#define IA32_JCC_IMM32_2 0x80 // encoding is +cc <imm32>
#define IA32_RET 0xC3 // no extra encoding
#define IA32_RETN 0xC2 // encoding is <imm16>
#define IA32_NEG_RM 0xF7 // encoding is /3
#define IA32_INC_REG 0x40 // encoding is +r
#define IA32_INC_RM 0xFF // encoding is /0
#define IA32_DEC_REG 0x48 // encoding is +r
#define IA32_DEC_RM 0xFF // encoding is /1
#define IA32_OR_REG_RM 0x0B // encoding is /r
#define IA32_AND_REG_RM 0x23 // encoding is /r
#define IA32_AND_EAX_IMM32 0x25 // encoding is <imm32>
#define IA32_AND_RM_IMM32 0x81 // encoding is /4
#define IA32_AND_RM_IMM8 0x83 // encoding is /4
#define IA32_NOT_RM 0xF7 // encoding is /2
#define IA32_DIV_RM 0xF7 // encoding is /6
#define IA32_MUL_RM 0xF7 // encoding is /4
#define IA32_IDIV_RM 0xF7 // encoding is /7
#define IA32_IMUL_RM 0xF7 // encoding is /5
#define IA32_IMUL_REG_IMM32 0x69 // encoding is /r
#define IA32_IMUL_REG_IMM8 0x6B // encoding is /r
#define IA32_IMUL_REG_RM_1 0x0F // encoding is _2
#define IA32_IMUL_REG_RM_2 0xAF // encoding is /r
#define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 <ib>
#define IA32_SHR_RM_1 0xD1 // encoding is /5
#define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 <ib>
#define IA32_SHL_RM_1 0xD1 // encoding is /4
#define IA32_SAR_RM_CL 0xD3 // encoding is /7
#define IA32_SAR_RM_1 0xD1 // encoding is /7
#define IA32_SHR_RM_CL 0xD3 // encoding is /5
#define IA32_SHL_RM_CL 0xD3 // encoding is /4
#define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 <ib>
#define IA32_SETCC_RM8_1 0x0F // opcode part 1
#define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits)
#define IA32_CMOVCC_RM_1 0x0F // opcode part 1
#define IA32_CMOVCC_RM_2 0x40 // encoding is +cc /r
#define IA32_XCHG_EAX_REG 0x90 // encoding is +r
#define IA32_LEA_REG_MEM 0x8D // encoding is /r
#define IA32_POP_REG 0x58 // encoding is +r
#define IA32_PUSH_REG 0x50 // encoding is +r
#define IA32_PUSH_RM 0xFF // encoding is /6
#define IA32_PUSH_IMM32 0x68 // encoding is <imm32>
#define IA32_PUSH_IMM8 0x6A // encoding is <imm8>
#define IA32_REP 0xF3 // no extra encoding
#define IA32_MOVSD 0xA5 // no extra encoding
#define IA32_MOVSB 0xA4 // no extra encoding
#define IA32_STOSD 0xAB // no extra encoding
#define IA32_CLD 0xFC // no extra encoding
#define IA32_PUSHAD 0x60 // no extra encoding
#define IA32_POPAD 0x61 // no extra encoding
#define IA32_NOP 0x90 // no extra encoding
#define IA32_INT3 0xCC // no extra encoding
#define IA32_FSTP_MEM32 0xD9 // encoding is /3
#define IA32_FSTP_MEM64 0xDD // encoding is /3
#define IA32_FLD_MEM32 0xD9 // encoding is /0
#define IA32_FLD_MEM64 0xDD // encoding is /0
#define IA32_FILD_MEM32 0xDB // encoding is /0
#define IA32_FADD_MEM32 0xD8 // encoding is /0
#define IA32_FADD_FPREG_ST0_1 0xDC // opcode part 1
#define IA32_FADD_FPREG_ST0_2 0xC0 // encoding is +r
#define IA32_FSUB_MEM32 0xD8 // encoding is /4
#define IA32_FMUL_MEM32 0xD8 // encoding is /1
#define IA32_FDIV_MEM32 0xD8 // encoding is /6
#define IA32_FSTCW_MEM16_1 0x9B // opcode part 1
#define IA32_FSTCW_MEM16_2 0xD9 // encoding is /7
#define IA32_FLDCW_MEM16 0xD9 // encoding is /5
#define IA32_FISTP_MEM32 0xDB // encoding is /3
#define IA32_FUCOMIP_1 0xDF // opcode part 1
#define IA32_FUCOMIP_2 0xE8 // encoding is +r
#define IA32_FSTP_FPREG_1 0xDD // opcode part 1
#define IA32_FSTP_FPREG_2 0xD8 // encoding is +r
#define IA32_MOVZX_R32_RM8_1 0x0F // opcode part 1
#define IA32_MOVZX_R32_RM8_2 0xB6 // encoding is /r
#define IA32_MOVZX_R32_RM16_1 0x0F // opcode part 1
#define IA32_MOVZX_R32_RM16_2 0xB7 // encoding is /r
namespace SourceHook
{
namespace Impl
{
typedef GenBuffer JitWriter;
inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm)
{
jit_uint8_t modrm = (mode << 6);
modrm |= (reg << 3);
modrm |= (rm);
return modrm;
}
//mode is the scaling method - NOSCALE ... SCALE8
//index is the register that is scaled
//base is the base register
inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t base)
{
jit_uint8_t sib = (mode << 6);
sib |= (index << 3);
sib |= (base);
return sib;
}
/***********************
* INCREMENT/DECREMENT *
***********************/
inline void IA32_Inc_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_INC_REG+reg);
}
inline void IA32_Inc_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, reg));
jit->write_byte(disp);
}
inline void IA32_Inc_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, reg));
jit->write_int32(disp);
}
inline void IA32_Inc_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale)
{
jit->write_ubyte(IA32_INC_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB));
jit->write_ubyte(ia32_sib(scale, reg, base));
}
inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_DEC_REG+reg);
}
inline void IA32_Dec_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, reg));
jit->write_byte(disp);
}
inline void IA32_Dec_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 1, reg));
jit->write_int32(disp);
}
inline void IA32_Dec_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale)
{
jit->write_ubyte(IA32_DEC_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 1, REG_SIB));
jit->write_ubyte(ia32_sib(scale, reg, base));
}
/****************
* BINARY LOGIC *
****************/
inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode)
{
jit->write_ubyte(IA32_XOR_RM_REG);
jit->write_ubyte(ia32_modrm(dest_mode, src, dest));
}
inline void IA32_Xor_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode)
{
jit->write_ubyte(IA32_XOR_REG_RM);
jit->write_ubyte(ia32_modrm(dest_mode, dest, src));
}
inline void IA32_Xor_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_XOR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
jit->write_byte(value);
}
inline void IA32_Xor_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_XOR_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
jit->write_int32(value);
}
inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_XOR_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_NEG_RM);
jit->write_ubyte(ia32_modrm(mode, 3, reg));
}
inline void IA32_Or_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_OR_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_And_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_AND_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_AND_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
jit->write_int32(value);
}
inline void IA32_And_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_AND_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
jit->write_byte(value);
}
inline void IA32_And_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_AND_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_NOT_RM);
jit->write_ubyte(ia32_modrm(mode, 2, reg));
}
inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 5, dest));
jit->write_ubyte(value);
}
inline void IA32_Shr_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_1);
jit->write_ubyte(ia32_modrm(mode, 5, dest));
}
inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 4, dest));
jit->write_ubyte(value);
}
inline void IA32_Shl_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_1);
jit->write_ubyte(ia32_modrm(mode, 4, dest));
}
inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 7, dest));
jit->write_ubyte(value);
}
inline void IA32_Sar_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 7, reg));
}
inline void IA32_Sar_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SAR_RM_1);
jit->write_ubyte(ia32_modrm(mode, 7, dest));
}
inline void IA32_Shr_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHR_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
}
inline void IA32_Shl_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SHL_RM_CL);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_XCHG_EAX_REG+reg);
}
/**********************
* ARITHMETIC (BASIC) *
**********************/
inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_byte(value);
}
inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_int32(value);
}
inline void IA32_Add_Rm_ImmAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode)
{
if (value >= SCHAR_MIN && value <= SCHAR_MAX)
IA32_Add_Rm_Imm8(jit, reg, static_cast<jit_int8_t>(value), mode);
else
IA32_Add_Rm_Imm32(jit, reg, value, mode);
}
inline void IA32_Add_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_ADD_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp8);
}
inline void IA32_Sub_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp8);
}
inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SUB_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
jit->write_int32(val);
}
inline void IA32_Sub_Rm_ImmAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode)
{
if (val >= SCHAR_MIN && val <= SCHAR_MAX)
IA32_Sub_Rm_Imm8(jit, reg, static_cast<jit_int8_t>(val), mode);
else
IA32_Sub_Rm_Imm32(jit, reg, val, mode);
}
inline void IA32_Sbb_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SBB_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Sbb_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_int8_t value, jit_uint8_t mode)
{
jit->write_ubyte(IA32_SBB_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 3, dest));
jit->write_byte(value);
}
inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_DIV_RM);
jit->write_ubyte(ia32_modrm(mode, 6, reg));
}
inline void IA32_IDiv_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IDIV_RM);
jit->write_ubyte(ia32_modrm(mode, 7, reg));
}
inline void IA32_Mul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MUL_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_IMul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IMUL_RM);
jit->write_ubyte(ia32_modrm(mode, 5, reg));
}
inline void IA32_IMul_Reg_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value)
{
jit->write_ubyte(IA32_IMUL_REG_IMM8);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_byte(value);
}
inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value)
{
jit->write_ubyte(IA32_IMUL_REG_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, reg));
jit->write_int32(value);
}
inline void IA32_IMul_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_IMUL_REG_RM_1);
jit->write_ubyte(IA32_IMUL_REG_RM_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_ADD_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp);
}
inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_ADD_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_byte(val);
}
inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_int32(val);
}
inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t mode)
{
jit->write_ubyte(IA32_ADD_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, dest));
jitoffs_t ptr = jit->get_outputpos();
jit->write_int32(0);
return ptr;
}
inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest));
jit->write_int32(disp32);
jit->write_byte(val);
}
inline void IA32_Add_RmEBP_Imm8_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_ADD_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, dest));
jit->write_byte(disp8);
jit->write_byte(val);
}
inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int8_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 5, dest));
jit->write_int32(disp32);
jit->write_byte(val);
}
inline void IA32_Sub_RmEBP_Imm8_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_SUB_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_byte(val);
}
/**
* Memory Instructions
*/
inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
}
inline void IA32_Lea_Reg_DispEBPRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_byte(0);
}
inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int8_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_byte(val);
}
inline void IA32_Lea_Reg_DispRegMultImm32(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, src_base));
jit->write_int32(val);
}
inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_index,
jit_uint8_t scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(scale, src_index, REG_IMM_BASE));
jit->write_int32(val);
}
inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base));
jit->write_byte(val);
}
inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
{
jit->write_ubyte(IA32_LEA_REG_MEM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base));
jit->write_int32(val);
}
inline void IA32_Lea_DispRegImmAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val)
{
if (val >= SCHAR_MIN && val <= SCHAR_MAX)
IA32_Lea_DispRegImm8(jit, dest, src_base, static_cast<jit_int8_t>(val));
else
IA32_Lea_DispRegImm32(jit, dest, src_base, val);
}
/**
* Stack Instructions
*/
inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_POP_REG+reg);
}
inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_PUSH_REG+reg);
}
inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val)
{
jit->write_ubyte(IA32_PUSH_IMM8);
jit->write_byte(val);
}
inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val)
{
jit->write_ubyte(IA32_PUSH_IMM32);
jit->write_int32(val);
}
inline void IA32_Pushad(JitWriter *jit)
{
jit->write_ubyte(IA32_PUSHAD);
}
inline void IA32_Popad(JitWriter *jit)
{
jit->write_ubyte(IA32_POPAD);
}
inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg));
jit->write_byte(disp8);
}
inline void IA32_Push_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp32)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 6, reg));
jit->write_int32(disp32);
}
inline void IA32_Push_Rm_DispAuto(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Push_Rm_Disp8(jit, reg, static_cast<jit_int8_t>(disp));
else
IA32_Push_Rm_Disp32(jit, reg, disp);
}
inline void IA32_Push_Rm_Disp8_ESP(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_PUSH_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
/**
* Moving from REGISTER/MEMORY to REGISTER
*/
inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Mov_Reg8_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Mov_Reg_RmESP(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_ESP));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp);
}
inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Mov_Reg8_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_REG8_RM8);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
}
inline void IA32_Mov_Reg_Rm_Disp_Reg_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
jit->write_byte(disp8);
}
inline void IA32_Mov_Reg_RmEBP_Disp_Reg(JitWriter *jit,
jit_uint8_t dest,
jit_uint8_t src_base,
jit_uint8_t src_index,
jit_uint8_t src_scale)
{
jit->write_ubyte(IA32_MOV_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB));
jit->write_ubyte(ia32_sib(src_scale, src_index, src_base));
jit->write_byte(0);
}
inline void IA32_Mov_Reg_Rm_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Mov_Reg_Rm(jit, dest, src, MOD_MEM_REG);
else if (disp <= SCHAR_MAX)
IA32_Mov_Reg_Rm_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Mov_Reg_Rm_Disp32(jit, dest, src, disp);
}
/**
* Moving from REGISTER to REGISTER/MEMORY
*/
inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM8_REG8);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Mov_RmESP_Reg(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_ESP));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest));
jit->write_byte(disp);
}
inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP32, src, dest));
jit->write_int32(disp);
}
inline void IA32_Mov_Rm_Reg_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Mov_Rm_Reg_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Mov_Rm_Reg_Disp32(jit, dest, src, disp);
}
inline void IA32_Mov_RmEBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
inline void IA32_Mov_Rm8EBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_MOV_RM8_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
inline void IA32_Mov_Rm16EBP_Reg_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_uint8_t src)
{
jit->write_ubyte(IA32_16BIT_PREFIX);
jit->write_ubyte(IA32_MOV_RM_REG);
jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
}
/**
* Moving from IMMEDIATE to REGISTER
*/
inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num)
{
jitoffs_t offs;
jit->write_ubyte(IA32_MOV_REG_IMM+dest);
offs = jit->get_outputpos();
jit->write_int32(num);
return offs;
}
inline void IA32_Mov_Rm_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 0, dest));
jit->write_int32(val);
}
inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int8_t disp8)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest));
jit->write_byte(disp8);
jit->write_int32(val);
}
inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit,
jit_uint8_t dest,
jit_int32_t val,
jit_int32_t disp32)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest));
jit->write_int32(disp32);
jit->write_int32(val);
}
inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit,
jit_uint8_t dest_base,
jit_uint8_t dest_index,
jit_uint8_t dest_scale,
jit_int32_t val)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base));
jit->write_byte(0);
jit->write_int32(val);
}
inline void IA32_Mov_ESP_Disp8_Imm32(JitWriter *jit, jit_int8_t disp8, jit_int32_t val)
{
jit->write_ubyte(IA32_MOV_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
jit->write_int32(val);
}
/**
* Floating Point Instructions
*/
inline void IA32_Fstcw_Mem16_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTCW_MEM16_1);
jit->write_ubyte(IA32_FSTCW_MEM16_2);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 7, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fldcw_Mem16_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FLDCW_MEM16);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 5, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fldcw_Mem16_Disp8_ESP(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_FLDCW_MEM16);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
inline void IA32_Fistp_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FISTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fistp_Mem32_Disp8_Esp(JitWriter *jit, jit_int8_t disp8)
{
jit->write_ubyte(IA32_FISTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
jit->write_byte(disp8);
}
inline void IA32_Fucomip_ST0_FPUreg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FUCOMIP_1);
jit->write_ubyte(IA32_FUCOMIP_2+reg);
}
inline void IA32_Fadd_FPUreg_ST0(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FADD_FPREG_ST0_1);
jit->write_ubyte(IA32_FADD_FPREG_ST0_2+reg);
}
inline void IA32_Fadd_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FADD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fadd_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FADD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fsub_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FSUB_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 4, src));
jit->write_byte(val);
}
inline void IA32_Fmul_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FMUL_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, src));
jit->write_byte(val);
}
inline void IA32_Fdiv_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FDIV_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, src));
jit->write_byte(val);
}
inline void IA32_Fild_Mem32(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FILD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_FSTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
}
inline void IA32_Fstp_Mem32_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_int32_t disp)
{
jit->write_ubyte(IA32_FSTP_MEM32);
if (disp > SCHAR_MIN && disp < SCHAR_MAX)
{
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, dest));
jit->write_byte(static_cast<jit_int8_t>(disp));
}
else
{
jit->write_ubyte(ia32_modrm(MOD_DISP32, 3, dest));
jit->write_byte(disp);
}
}
inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest)
{
jit->write_ubyte(IA32_FSTP_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest));
}
inline void IA32_Fstp_Mem64_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_int32_t disp)
{
jit->write_ubyte(IA32_FSTP_MEM64);
if (disp > SCHAR_MIN && disp < SCHAR_MAX)
{
jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, dest));
jit->write_byte(static_cast<jit_int8_t>(disp));
}
else
{
jit->write_ubyte(ia32_modrm(MOD_DISP32, 3, dest));
jit->write_byte(disp);
}
}
inline void IA32_Fstp_Mem32_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTP_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fstp_Mem64_ESP(JitWriter *jit)
{
jit->write_ubyte(IA32_FSTP_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Fstp_FPUreg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_FSTP_FPREG_1);
jit->write_ubyte(IA32_FSTP_FPREG_2+reg);
}
inline void IA32_Fld_Mem32(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fld_Mem64(JitWriter *jit, jit_uint8_t src)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(val);
}
inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
{
jit->write_ubyte(IA32_FLD_MEM32);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
jit->write_int32(val);
}
inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val)
{
jit->write_ubyte(IA32_FLD_MEM64);
jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src));
jit->write_int32(val);
}
inline void IA32_Fld_Mem32_DispAuto(JitWriter *jit, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Fld_Mem32(jit, src);
else if (disp <= SCHAR_MAX)
IA32_Fld_Mem32_Disp8(jit, src, static_cast<jit_int8_t>(disp));
else
IA32_Fld_Mem32_Disp32(jit, src, disp);
}
inline void IA32_Fld_Mem64_DispAuto(JitWriter *jit, jit_uint8_t src, jit_int32_t disp)
{
if (disp == 0)
IA32_Fld_Mem64(jit, src);
else if (disp <= SCHAR_MAX)
IA32_Fld_Mem64_Disp8(jit, src, static_cast<jit_int8_t>(disp));
else
IA32_Fld_Mem64_Disp32(jit, src, disp);
}
/**
* Move data with zero extend
*/
inline void IA32_Movzx_Reg32_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Movzx_Reg32_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Movzx_Reg32_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM8_1);
jit->write_ubyte(IA32_MOVZX_R32_RM8_2);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Movzx_Reg32_Rm8_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Movzx_Reg32_Rm8_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Movzx_Reg32_Rm8_Disp32(jit, dest, src, disp);
}
inline void IA32_Movzx_Reg32_Rm16(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Movzx_Reg32_Rm16_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src));
jit->write_byte(disp);
}
inline void IA32_Movzx_Reg32_Rm16_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
jit->write_ubyte(IA32_MOVZX_R32_RM16_1);
jit->write_ubyte(IA32_MOVZX_R32_RM16_2);
jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src));
jit->write_int32(disp);
}
inline void IA32_Movzx_Reg32_Rm16_DispAuto(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp)
{
if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
IA32_Movzx_Reg32_Rm16_Disp8(jit, dest, src, static_cast<jit_int8_t>(disp));
else
IA32_Movzx_Reg32_Rm16_Disp32(jit, dest, src, disp);
}
/**
* Branching/Jumping
*/
inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM+cond);
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM32);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JMP_IMM8);
ptr = jit->get_outputpos();
jit->write_byte(disp);
return ptr;
}
inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_JCC_IMM32_1);
jit->write_ubyte(IA32_JCC_IMM32_2+cond);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_JMP_RM);
jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg));
}
inline void IA32_Jump_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_JMP_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp)
{
jitoffs_t ptr;
jit->write_ubyte(IA32_CALL_IMM32);
ptr = jit->get_outputpos();
jit->write_int32(disp);
return ptr;
}
inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg)
{
jit->write_ubyte(IA32_CALL_RM);
jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg));
}
inline void IA32_Call_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CALL_RM);
jit->write_ubyte(ia32_modrm(mode, 4, reg));
}
inline void IA32_Return(JitWriter *jit)
{
jit->write_ubyte(IA32_RET);
}
inline void IA32_Return_Popstack(JitWriter *jit, unsigned short bytes)
{
jit->write_ubyte(IA32_RETN);
jit->write_ushort(bytes);
}
inline void IA32_Test_Rm_Reg(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode)
{
jit->write_ubyte(IA32_TEST_RM_REG);
jit->write_ubyte(ia32_modrm(mode, reg2, reg1));
}
inline void IA32_Test_Rm_Reg8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode)
{
jit->write_ubyte(IA32_TEST_RM_REG8);
jit->write_ubyte(ia32_modrm(mode, reg2, reg1));
}
inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CMP_RM_REG);
jit->write_ubyte(ia32_modrm(mode, src, dest));
}
inline void IA32_Cmp_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(mode, dest, src));
}
inline void IA32_Cmp_Reg_Rm_ESP(JitWriter *jit, jit_uint8_t cmpreg)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, cmpreg, REG_SIB));
jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP));
}
inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8)
{
jit->write_ubyte(IA32_CMP_REG_RM);
jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2));
jit->write_byte(disp8);
}
inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8)
{
jit->write_ubyte(IA32_CMP_RM_IMM8);
jit->write_ubyte(ia32_modrm(mode, 7, rm));
jit->write_byte(imm8);
}
inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32)
{
jit->write_ubyte(IA32_CMP_RM_IMM32);
jit->write_ubyte(ia32_modrm(mode, 7, rm));
jit->write_int32(imm32);
}
inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8, jit_int32_t imm32)
{
jit->write_ubyte(IA32_CMP_RM_IMM32);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg));
jit->write_byte(disp8);
jit->write_int32(imm32);
}
inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8)
{
jit->write_ubyte(IA32_CMP_RM_IMM8);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg));
jit->write_byte(disp);
jit->write_byte(imm8);
}
inline void IA32_Cmp_Al_Imm8(JitWriter *jit, jit_int8_t value)
{
jit->write_ubyte(IA32_CMP_AL_IMM32);
jit->write_byte(value);
}
inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value)
{
jit->write_ubyte(IA32_CMP_EAX_IMM32);
jit->write_int32(value);
}
inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond)
{
jit->write_ubyte(IA32_SETCC_RM8_1);
jit->write_ubyte(IA32_SETCC_RM8_2+cond);
jit->write_ubyte(ia32_modrm(MOD_REG, 0, reg));
}
inline void IA32_CmovCC_Rm(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond)
{
jit->write_ubyte(IA32_CMOVCC_RM_1);
jit->write_ubyte(IA32_CMOVCC_RM_2+cond);
jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src));
}
inline void IA32_CmovCC_Rm_Disp8(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond, jit_int8_t disp)
{
jit->write_ubyte(IA32_CMOVCC_RM_1);
jit->write_ubyte(IA32_CMOVCC_RM_2+cond);
jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src));
jit->write_byte(disp);
}
inline void IA32_Cmpsb(JitWriter *jit)
{
jit->write_ubyte(IA32_CMPSB);
}
inline void IA32_Rep(JitWriter *jit)
{
jit->write_ubyte(IA32_REP);
}
inline void IA32_Movsd(JitWriter *jit)
{
jit->write_ubyte(IA32_MOVSD);
}
inline void IA32_Movsb(JitWriter *jit)
{
jit->write_ubyte(IA32_MOVSB);
}
inline void IA32_Stosd(JitWriter *jit)
{
jit->write_ubyte(IA32_STOSD);
}
inline void IA32_Cld(JitWriter *jit)
{
jit->write_ubyte(IA32_CLD);
}
}
}
#endif //_INCLUDE_JIT_X86_MACROS_H

View File

@ -0,0 +1,6 @@
:: Generates everything
:: Usage:
:: generate.bat <num-of-arguments>
..\generate\shworker iter testhookmangen.hxx testhookmangen.h %1

View File

@ -46,6 +46,7 @@ DECL_TEST(Multi);
DECL_TEST(Ref);
DECL_TEST(RefRet);
DECL_TEST(VPHooks);
DECL_TEST(HookManGen);
int main(int argc, char *argv[])
{
@ -68,6 +69,7 @@ int main(int argc, char *argv[])
DO_TEST(Ref);
DO_TEST(RefRet);
DO_TEST(VPHooks);
DO_TEST(HookManGen);
cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
cout << "Total: " << passed + failed << endl;

View File

@ -17,6 +17,7 @@ struct CAutoPtrDestruction
CAutoPtrDestruction(T *p) : m_Ptr(p) { }
~CAutoPtrDestruction() { if (m_Ptr) delete m_Ptr; }
void clear() { m_Ptr = NULL; }
void set(T *ptr) { m_Ptr = ptr; }
};
struct CSHPtrAutoDestruction

View File

@ -31,9 +31,25 @@ struct State
return (typeid(other) == typeid(this)) ? true : false;
}
virtual bool Ignore()
{
return false;
}
virtual void Dump() = 0;
};
struct IgnoreState : public State
{
virtual bool Ignore()
{
return true;
}
virtual void Dump()
{
}
};
typedef std::list<State*> StateList;
namespace
{
@ -53,6 +69,8 @@ namespace
State *cs = va_arg(argptr, State*);
if (!cs)
break;
if (cs->Ignore())
continue;
requiredstates.push_back(cs);
}
va_end(argptr);
@ -86,6 +104,14 @@ namespace
}
}
if (!ok && g_Verbose)
{
std::cout << std::endl << "FAIL: Should be:" << std::endl;
DumpStates(&requiredstates);
std::cout << std::endl << "FAIL: Is:" << std::endl;
DumpStates(sl);
}
for (StateList::iterator iter = requiredstates.begin(); iter != requiredstates.end(); ++iter)
delete *iter;
for (StateList::iterator iter = sl->begin(); iter != sl->end(); ++iter)

View File

@ -0,0 +1,470 @@
#include <string>
#include "sourcehook.h"
#include "sourcehook_test.h"
#include "testevents.h"
#include "sourcehook_hookmangen.h"
// TESTHOOKMANGEN
// Test automatic hookman generation
// Tests void and non-void functions
// 0 to 6 params:
// integer-type, float-type, plain-old-data struct and objects with ctors/dtors
// both byval and byref
// also tests ignore/supercede
// also tests recalls
// :TODO: test override as well
namespace
{
#include "testhookmangen.h"
StateList g_States;
SourceHook::ISourceHook *g_SHPtr;
SourceHook::Plugin g_PLID;
// PtrBuf(ptr) gives ptrs unique numbers
// in the order they appear
SourceHook::List<const void*> g_PtrHash;
bool g_Inside_LeafFunc = false; // inside a hook or a func
template <class T>
int PtrBuf(T ptr)
{
int a = 0;
const void *vptr = reinterpret_cast<const void*>(ptr);
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end(); ++iter)
{
if (*iter == vptr)
return a;
else
++a;
}
g_PtrHash.push_back(vptr);
return static_cast<int>(g_PtrHash.size()) - 1;
}
template <class T>
T PtrBufPtr(T ptr)
{
PtrBuf(ptr);
return ptr;
}
void PtrBuf_Clear(int leave_in = 0)
{
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end();)
{
if (--leave_in < 0)
iter = g_PtrHash.erase(iter);
else
++iter;
}
}
// POD / Object types
template <int MYSIZE>
struct POD
{
char x[MYSIZE];
bool operator==(const POD<MYSIZE> &other)
{
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
}
};
template <int MYSIZE>
std::ostream& operator <<(std::ostream &os, const POD<MYSIZE> &obj)
{
os << "Some POD!";
return os;
}
MAKE_STATE_1(State_ObjOCtor_Called, int /*MYSIZE*/);
MAKE_STATE_1(State_ObjCCtor_Called, int /*MYSIZE*/);
MAKE_STATE_1(State_ObjODtor_Called, int /*MYSIZE*/);
template <int MYSIZE>
struct Object
{
char x[MYSIZE];
Object(char initch)
{
memset(reinterpret_cast<void*>(x), initch, MYSIZE);
if (!g_Inside_LeafFunc)
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
}
Object()
{
if (!g_Inside_LeafFunc)
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
}
Object(const Object<MYSIZE> & other)
{
memcpy(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE);
if (!g_Inside_LeafFunc)
ADD_STATE(State_ObjCCtor_Called(MYSIZE));
}
~Object()
{
if (!g_Inside_LeafFunc)
ADD_STATE(State_ObjODtor_Called(MYSIZE));
}
bool operator==(const Object<MYSIZE> &other)
{
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
}
};
template <int MYSIZE>
std::ostream& operator <<(std::ostream &os, const Object<MYSIZE> &obj)
{
os << "Some Obj!";
return os;
}
// "Increment" something: (reproducible change for recall tests)
// integer: ++
// float: += 1.3
// pod/object: x[i]++, 0 <= i < MYSIZE
template <class T>
struct Increment
{
static void Incr(T &what)
{
++what;
}
};
template<>
struct Increment<float>
{
static void Incr(float &what)
{
what += 1.3f;
}
};
template<>
struct Increment<double>
{
static void Incr(double &what)
{
what += 1.3;
}
};
template<int MYSIZE>
struct Increment< POD<MYSIZE> >
{
static void Incr(POD<MYSIZE> &what)
{
for (int i = 0; i < MYSIZE; ++i)
++ what.x[i];
}
};
template<int MYSIZE>
struct Increment< Object<MYSIZE> >
{
static void Incr(Object<MYSIZE> &what)
{
for (int i = 0; i < MYSIZE; ++i)
++ what.x[i];
}
};
// MyDelegate base class for other delegates
class MyDelegate : public SourceHook::ISHDelegate
{
// Unneeded
// because we don't use old SH_REMOVE_HOOK syntax
virtual bool IsEqual(SourceHook::ISHDelegate *pOtherDeleg)
{
return false;
}
virtual void DeleteThis()
{
delete this;
}
};
THGM_MAKE_TEST0_void(0);
THGM_SETUP_PI0(0);
THGM_MAKE_TEST1_void(1, char);
THGM_SETUP_PI1(1, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(2, short);
THGM_SETUP_PI1(2, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(3, int);
THGM_SETUP_PI1(3, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(4, float);
THGM_SETUP_PI1(4, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(5, double);
THGM_SETUP_PI1(5, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST5_void(6, char, short, int, float, double);
THGM_SETUP_PI5(6,
char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal
);
THGM_MAKE_TEST2_void(7, char&, double&);
THGM_SETUP_PI2(7,
char&, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByRef,
double&, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByRef
);
THGM_MAKE_TEST1_void(8, POD<7>);
THGM_SETUP_PI1(8, POD<7>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(9, POD<600>);
THGM_SETUP_PI1(9, POD<600>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST1_void(10, POD<600> &);
THGM_SETUP_PI1(10, POD<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef);
THGM_MAKE_TEST2_void(11, Object<3>, Object<600>&);
THGM_SETUP_PI2(11,
Object<3>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor,
Object<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor
);
THGM_MAKE_TEST0(101, char);
THGM_SETUP_PI0(101);
THGM_SETUP_RI(101, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(102, short);
THGM_SETUP_PI0(102);
THGM_SETUP_RI(102, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(103, int);
THGM_SETUP_PI0(103);
THGM_SETUP_RI(103, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(104, float);
THGM_SETUP_PI0(104);
THGM_SETUP_RI(104, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
THGM_MAKE_TEST0(105, double);
THGM_SETUP_PI0(105);
THGM_SETUP_RI(105, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
}
bool TestHookManGen(std::string &error)
{
GET_SHPTR(g_SHPtr);
g_PLID = 1337;
THGM_DO_TEST_void(0, ());
THGM_DO_TEST_void(1, (100));
THGM_DO_TEST_void(2, (0x1F00));
THGM_DO_TEST_void(3, (0x1F000000));
THGM_DO_TEST_void(4, (0.5f));
THGM_DO_TEST_void(5, (5.5));
THGM_DO_TEST_void(6, (100, 0x1f00, 0x1f000000, 0.5f, 5.5));
char a = 5;
double b = 233.33;
THGM_DO_TEST_void(7, (a, b));
POD<7> pod7 = {78};
THGM_DO_TEST_void(8, (pod7));
POD<600> pod600 = {34};
THGM_DO_TEST_void(9, (pod600));
THGM_DO_TEST_void(10, (pod600));
// Test11: Special: constructors/destructors
PtrBuf_Clear();
Object<3> obj3(33);
Object<600> obj600(21);
CHECK_STATES((&g_States,
new State_ObjOCtor_Called(3),
new State_ObjOCtor_Called(600),
NULL), "Test11 Part0");
setuppi_11();
g_Genc11 = new SourceHook::Impl::GenContext(&protoinfo_11, 0, 0, g_SHPtr);
g_Genc_ad11.set(g_Genc11);
SourceHook::HookManagerPubFunc myhookman11 = g_Genc11->Generate();
int hook1_11, hook2_11, hook3_11, hook4_11;
TestClass11 *pTest11 = new TestClass11;
CAutoPtrDestruction<TestClass11> apd11(pTest11);
/* no hooks - no hooks */
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part1");
g_Inside_LeafFunc = false;
/* hook1 - no hooks */
THGM_ADD_HOOK(11, 1);
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg1_11(pTest11, 0, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part2");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(11, 1);
/* hook1, hook2 - hook3, hook4 */
THGM_ADD_HOOK(11, 1);
THGM_ADD_HOOK(11, 2);
THGM_ADD_HOOK(11, 3);
THGM_ADD_HOOK(11, 4);
PtrBuf_Clear();
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg1_11(pTest11, 0, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg2_11(pTest11, 1, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg3_11(pTest11, 2, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg4_11(pTest11, 3, ParamState_m11 (obj3, obj600)),
new State_ObjODtor_Called(3),
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part3");
g_Inside_LeafFunc = false;
/* hook1 - hook3, hook4 WITH RECALLS */
THGM_REMOVE_HOOK(11, 2);
PtrBuf_Clear();
TestClass11::ms_DoRecall = true;
pTest11->Func(obj3, obj600);
g_Inside_LeafFunc = true;
CHECK_STATES((&g_States,
new State_ObjCCtor_Called(3),
new State_ObjCCtor_Called(3),
new State_Deleg1_11(pTest11, 0 /* first deleg ptr */, ParamState_m11 (obj3, obj600)),
// recall !
// second hookfunc -> new copy
new State_ObjCCtor_Called(3),
// in second hookfunc now
// -> calls orig func
new State_ObjCCtor_Called(3),
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)(1)),
new State_ObjODtor_Called(3),
// calls first posthook
new State_ObjCCtor_Called(3),
new State_Deleg3_11(pTest11, 1 /* second deleg ptr */, ParamState_m11 (obj3, obj600)(1)),
// recall!
// third hookfunc -> new copy
new State_ObjCCtor_Called(3),
// calls second posthook
new State_ObjCCtor_Called(3),
new State_Deleg4_11(pTest11, 2 /* third deleg ptr */, ParamState_m11 (obj3, obj600)(2)),
// recall!
// fourth hookfunc -> new copy
new State_ObjCCtor_Called(3),
// has nothing to do though!
// fourth hookfunc done -> ret
new State_ObjODtor_Called(3),
// third hookfunc done -> ret
new State_ObjODtor_Called(3),
// ret from hookhandler which did the recall
new State_ObjODtor_Called(3),
// second hookfunc done -> ret
new State_ObjODtor_Called(3),
// ret from hookhandler which did the recall
new State_ObjODtor_Called(3),
// deleg1's instance
new State_ObjODtor_Called(3),
// first hookfunc done -> ret
new State_ObjODtor_Called(3),
NULL), "Test" "11" " Part4");
g_Inside_LeafFunc = false;
THGM_REMOVE_HOOK(11, 1);
THGM_REMOVE_HOOK(11, 3);
THGM_REMOVE_HOOK(11, 4);
THGM_DO_TEST(101, ());
THGM_DO_TEST(102, ());
THGM_DO_TEST(103, ());
THGM_DO_TEST(104, ());
THGM_DO_TEST(105, ());
// Shutdown now!
// If we don't SH will auto-shutdown _after_ genc's destructor is called
// -> crash
Test_CompleteShutdown(g_SHPtr);
return true;
}

View File

@ -0,0 +1,2090 @@
// Strip &
template <class T> struct StripRef
{
typedef T type;
};
template <class T> struct StripRef<T&>
{
typedef T type;
};
// Address of constructor/destructor
// (using wrappers)
template <class T>
class Ctor_Thunk
{
public:
void NormalConstructor()
{
new(this) T;
}
void CopyConstructor(const T &other)
{
new(this) T(other);
}
void Destructor()
{
reinterpret_cast<T*>(this)->~T();
}
};
template <class T>
void *FindFuncAddr(T mfp)
{
if (sizeof(mfp) != sizeof(void*))
return NULL;
else
return fastdelegate::detail::horrible_cast<void*>(mfp);
}
// Reference carrier
template <class T> struct MyRefCarrier
{
typedef T type;
};
template <class T> struct MyRefCarrier<T&>
{
class type
{
T *m_StoredRef;
public:
type() : m_StoredRef(NULL)
{
}
type(T& ref) : m_StoredRef(&ref)
{
}
T& operator= (T& ref)
{
m_StoredRef = &ref;
return ref;
}
operator T& () const
{
return *m_StoredRef;
}
bool operator== (const typename MyRefCarrier<T&>::type &other)
{
return m_StoredRef == other.m_StoredRef;
}
friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier<T&>::type &obj)
{
os << *obj.m_StoredRef;
return os;
}
};
};
// Stores parameter status
template<int dummy>
struct ParamState0
{
bool operator==(const ParamState0<dummy> &other)
{
return true
;
}
ParamState0()
{
}
ParamState0<dummy> & operator() (int incrsteps)
{
return *this;
}
};
std::ostream& operator <<(std::ostream &os,const ParamState0<0> &obj)
{
;
return os;
}
template<int dummy, class p1>
struct ParamState1
{
typename MyRefCarrier<p1>::type m_1;
bool operator==(const ParamState1<dummy, p1> &other)
{
return true
&& m_1 == other.m_1
;
}
ParamState1(p1 a1) : m_1(a1)
{
}
ParamState1<dummy, p1> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
return *this;
}
};
template<class p1>
std::ostream& operator <<(std::ostream &os,const ParamState1<0, p1> &obj)
{
os << obj.m_1;
return os;
}
template<int dummy, class p1, class p2>
struct ParamState2
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2;
bool operator==(const ParamState2<dummy, p1, p2> &other)
{
return true
&& m_2 == other.m_2 && m_2 == other.m_2
;
}
ParamState2(p1 a1, p2 a2) : m_1(a1), m_2(a2)
{
}
ParamState2<dummy, p1, p2> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p2 >::type>::Incr(m_2);
return *this;
}
};
template<class p1, class p2>
std::ostream& operator <<(std::ostream &os,const ParamState2<0, p1, p2> &obj)
{
os << obj.m_1<< obj.m_2;
return os;
}
template<int dummy, class p1, class p2, class p3>
struct ParamState3
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3;
bool operator==(const ParamState3<dummy, p1, p2, p3> &other)
{
return true
&& m_3 == other.m_3 && m_3 == other.m_3 && m_3 == other.m_3
;
}
ParamState3(p1 a1, p2 a2, p3 a3) : m_1(a1), m_2(a2), m_3(a3)
{
}
ParamState3<dummy, p1, p2, p3> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p2 >::type>::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p3 >::type>::Incr(m_3);
return *this;
}
};
template<class p1, class p2, class p3>
std::ostream& operator <<(std::ostream &os,const ParamState3<0, p1, p2, p3> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4>
struct ParamState4
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4;
bool operator==(const ParamState4<dummy, p1, p2, p3, p4> &other)
{
return true
&& m_4 == other.m_4 && m_4 == other.m_4 && m_4 == other.m_4 && m_4 == other.m_4
;
}
ParamState4(p1 a1, p2 a2, p3 a3, p4 a4) : m_1(a1), m_2(a2), m_3(a3), m_4(a4)
{
}
ParamState4<dummy, p1, p2, p3, p4> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p2 >::type>::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p3 >::type>::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p4 >::type>::Incr(m_4);
return *this;
}
};
template<class p1, class p2, class p3, class p4>
std::ostream& operator <<(std::ostream &os,const ParamState4<0, p1, p2, p3, p4> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4, class p5>
struct ParamState5
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4; typename MyRefCarrier<p5>::type m_5;
bool operator==(const ParamState5<dummy, p1, p2, p3, p4, p5> &other)
{
return true
&& m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5 && m_5 == other.m_5
;
}
ParamState5(p1 a1, p2 a2, p3 a3, p4 a4, p5 a5) : m_1(a1), m_2(a2), m_3(a3), m_4(a4), m_5(a5)
{
}
ParamState5<dummy, p1, p2, p3, p4, p5> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p2 >::type>::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p3 >::type>::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p4 >::type>::Incr(m_4);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p5 >::type>::Incr(m_5);
return *this;
}
};
template<class p1, class p2, class p3, class p4, class p5>
std::ostream& operator <<(std::ostream &os,const ParamState5<0, p1, p2, p3, p4, p5> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4<< obj.m_5;
return os;
}
template<int dummy, class p1, class p2, class p3, class p4, class p5, class p6>
struct ParamState6
{
typename MyRefCarrier<p1>::type m_1; typename MyRefCarrier<p2>::type m_2; typename MyRefCarrier<p3>::type m_3; typename MyRefCarrier<p4>::type m_4; typename MyRefCarrier<p5>::type m_5; typename MyRefCarrier<p6>::type m_6;
bool operator==(const ParamState6<dummy, p1, p2, p3, p4, p5, p6> &other)
{
return true
&& m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6 && m_6 == other.m_6
;
}
ParamState6(p1 a1, p2 a2, p3 a3, p4 a4, p5 a5, p6 a6) : m_1(a1), m_2(a2), m_3(a3), m_4(a4), m_5(a5), m_6(a6)
{
}
ParamState6<dummy, p1, p2, p3, p4, p5, p6> & operator() (int incrsteps)
{
int i;
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p1 >::type>::Incr(m_1);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p2 >::type>::Incr(m_2);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p3 >::type>::Incr(m_3);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p4 >::type>::Incr(m_4);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p5 >::type>::Incr(m_5);
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p6 >::type>::Incr(m_6);
return *this;
}
};
template<class p1, class p2, class p3, class p4, class p5, class p6>
std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, p5, p6> &obj)
{
os << obj.m_1<< obj.m_2<< obj.m_3<< obj.m_4<< obj.m_5<< obj.m_6;
return os;
}
#define CAT2(a, b) a##b
#define CAT3(a, b, c) a##b##c
#define CAT4(a, b, c, d) a##b##c##d
// hook1: pre ignore
// hook2: pre supercede
// hook3: post ignore
// hook4: post supercede
#define THGM_MAKE_TEST0_void(id) \
struct TestClass##id; \
typedef ParamState0<0 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id())); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, ()); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, ()); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, ()); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, ()); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[0+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[0+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 0, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST0(id, ret_type) \
struct TestClass##id; \
typedef ParamState0<0 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id())); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, ()); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, ()); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, ()); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call() \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id())); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
\
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, ()); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[0+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[0+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 0, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI0(id) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
\
\
\
\
\
}
#define THGM_MAKE_TEST1_void(id, param1) \
struct TestClass##id; \
typedef ParamState1<0, param1 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[1+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[1+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 1, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST1(id, ret_type, param1) \
struct TestClass##id; \
typedef ParamState1<0, param1 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[1+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[1+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 1, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI1(id, p1_type, p1_passtype, p1_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; \
}
#define THGM_MAKE_TEST2_void(id, param1, param2) \
struct TestClass##id; \
typedef ParamState2<0, param1, param2 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[2+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[2+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 2, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST2(id, ret_type, param1, param2) \
struct TestClass##id; \
typedef ParamState2<0, param1, param2 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[2+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[2+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 2, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI2(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; \
}
#define THGM_MAKE_TEST3_void(id, param1, param2, param3) \
struct TestClass##id; \
typedef ParamState3<0, param1, param2, param3 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[3+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[3+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 3, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST3(id, ret_type, param1, param2, param3) \
struct TestClass##id; \
typedef ParamState3<0, param1, param2, param3 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[3+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[3+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 3, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI3(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; \
}
#define THGM_MAKE_TEST4_void(id, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ParamState4<0, param1, param2, param3, param4 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[4+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[4+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 4, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST4(id, ret_type, param1, param2, param3, param4) \
struct TestClass##id; \
typedef ParamState4<0, param1, param2, param3, param4 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[4+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[4+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 4, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI4(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL; \
}
#define THGM_MAKE_TEST5_void(id, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ParamState5<0, param1, param2, param3, param4, param5 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[5+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[5+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 5, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST5(id, ret_type, param1, param2, param3, param4, param5) \
struct TestClass##id; \
typedef ParamState5<0, param1, param2, param3, param4, param5 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4, p5)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[5+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[5+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 5, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI5(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags, p5_type, p5_passtype, p5_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; paraminfos_##id[5].size = sizeof(p5_type); paraminfos_##id[5].type = p5_passtype; paraminfos_##id[5].flags = p5_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : NULL; \
}
#define THGM_MAKE_TEST6_void(id, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, param6 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[6+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[6+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 6, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST6(id, ret_type, param1, param2, param3, param4, param5, param6) \
struct TestClass##id; \
typedef ParamState6<0, param1, param2, param3, param4, param5, param6 > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(param1 p1, param2 p2, param3 p3, param4 p4, param5 p5, param6 p6) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(p1, p2, p3, p4, p5, p6))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
Increment<StripRef< param1 >::type>::Incr(p1);Increment<StripRef< param2 >::type>::Incr(p2);Increment<StripRef< param3 >::type>::Incr(p3);Increment<StripRef< param4 >::type>::Incr(p4);Increment<StripRef< param5 >::type>::Incr(p5);Increment<StripRef< param6 >::type>::Incr(p6); \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (p1, p2, p3, p4, p5, p6)); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[6+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[6+1]; \
SourceHook::ProtoInfo protoinfo_##id = { 6, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI6(id, p1_type, p1_passtype, p1_flags, p2_type, p2_passtype, p2_flags, p3_type, p3_passtype, p3_flags, p4_type, p4_passtype, p4_flags, p5_type, p5_passtype, p5_flags, p6_type, p6_passtype, p6_flags) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
paraminfos_##id[1].size = sizeof(p1_type); paraminfos_##id[1].type = p1_passtype; paraminfos_##id[1].flags = p1_flags; paraminfos_##id[2].size = sizeof(p2_type); paraminfos_##id[2].type = p2_passtype; paraminfos_##id[2].flags = p2_flags; paraminfos_##id[3].size = sizeof(p3_type); paraminfos_##id[3].type = p3_passtype; paraminfos_##id[3].flags = p3_flags; paraminfos_##id[4].size = sizeof(p4_type); paraminfos_##id[4].type = p4_passtype; paraminfos_##id[4].flags = p4_flags; paraminfos_##id[5].size = sizeof(p5_type); paraminfos_##id[5].type = p5_passtype; paraminfos_##id[5].flags = p5_flags; paraminfos_##id[6].size = sizeof(p6_type); paraminfos_##id[6].type = p6_passtype; paraminfos_##id[6].flags = p6_flags; \
\
paraminfos2_##id[1].pNormalCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[2].pNormalCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[3].pNormalCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[4].pNormalCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[5].pNormalCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::NormalConstructor) : NULL; paraminfos2_##id[6].pNormalCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::NormalConstructor) : NULL; \
paraminfos2_##id[1].pCopyCtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[2].pCopyCtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[3].pCopyCtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[4].pCopyCtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[5].pCopyCtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::CopyConstructor) : NULL; paraminfos2_##id[6].pCopyCtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::CopyConstructor) : NULL; \
paraminfos2_##id[1].pDtor = (paraminfos_##id[1].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p1_type >::type>::Destructor) : NULL; paraminfos2_##id[2].pDtor = (paraminfos_##id[2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p2_type >::type>::Destructor) : NULL; paraminfos2_##id[3].pDtor = (paraminfos_##id[3].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p3_type >::type>::Destructor) : NULL; paraminfos2_##id[4].pDtor = (paraminfos_##id[4].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p4_type >::type>::Destructor) : NULL; paraminfos2_##id[5].pDtor = (paraminfos_##id[5].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p5_type >::type>::Destructor) : NULL; paraminfos2_##id[6].pDtor = (paraminfos_##id[6].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p6_type >::type>::Destructor) : NULL; \
}
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
void setupri_##id() \
{ \
protoinfo_##id.retPassInfo.size = sizeof(ret_type); \
protoinfo_##id.retPassInfo.type = ret_passtype; \
protoinfo_##id.retPassInfo.flags = ret_flags; \
\
protoinfo_##id.retPassInfo2.pNormalCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL; \
protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL; \
protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : NULL; \
}
#define THGM_ADD_HOOK(id, num) \
CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pTest##id), \
0, myhookman##id, PtrBufPtr(new TestClass##id::Delegate##num), num >= 3);
#define THGM_REMOVE_HOOK(id, num) \
g_SHPtr->RemoveHookByID(CAT4(hook, num, _, id));
#define THGM_CALLS_void(id, call_params) \
pTest##id->Func call_params; \
SH_CALL(pTest##id, &TestClass##id::Func) call_params;
#define THGM_DO_TEST_void(id, call_params) \
setuppi_##id(); \
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
g_Genc_ad##id.set(g_Genc##id); \
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - no hooks */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part2"); \
THGM_REMOVE_HOOK(id, 1); \
\
/* no hooks - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part3"); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 2); \
THGM_REMOVE_HOOK(id, 3); \
/* hook1, hook2 - hook3, hook4 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \
CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall");
#define THGM_DO_TEST(id, call_params) \
setuppi_##id(); \
setupri_##id(); \
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
g_Genc_ad##id.set(g_Genc##id); \
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS(id, call_params, 0, 0, "Part1"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - no hooks */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_CALLS(id, call_params, 0, 0, "Part2"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part2"); \
THGM_REMOVE_HOOK(id, 1); \
\
/* no hooks - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part3"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part3"); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part4"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 2, 0, "Part5"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 2); \
THGM_REMOVE_HOOK(id, 3); \
/* hook1, hook2 - hook3, hook4 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS(id, call_params, 4, 0, "Part7"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);

View File

@ -0,0 +1,578 @@
// Strip &
template <class T> struct StripRef
{
typedef T type;
};
template <class T> struct StripRef<T&>
{
typedef T type;
};
// Address of constructor/destructor
// (using wrappers)
template <class T>
class Ctor_Thunk
{
public:
void NormalConstructor()
{
new(this) T;
}
void CopyConstructor(const T &other)
{
new(this) T(other);
}
void Destructor()
{
reinterpret_cast<T*>(this)->~T();
}
};
template <class T>
void *FindFuncAddr(T mfp)
{
if (sizeof(mfp) != sizeof(void*))
return NULL;
else
return fastdelegate::detail::horrible_cast<void*>(mfp);
}
// Reference carrier
template <class T> struct MyRefCarrier
{
typedef T type;
};
template <class T> struct MyRefCarrier<T&>
{
class type
{
T *m_StoredRef;
public:
type() : m_StoredRef(NULL)
{
}
type(T& ref) : m_StoredRef(&ref)
{
}
T& operator= (T& ref)
{
m_StoredRef = &ref;
return ref;
}
operator T& () const
{
return *m_StoredRef;
}
bool operator== (const typename MyRefCarrier<T&>::type &other)
{
return m_StoredRef == other.m_StoredRef;
}
friend std::ostream& operator <<(std::ostream &os,const typename MyRefCarrier<T&>::type &obj)
{
os << *obj.m_StoredRef;
return os;
}
};
};
// Stores parameter status
@[$1,0,$a:
template<int dummy@[$2,1,$1:, class p$2@]>
struct ParamState$1
{
@[$2,1,$1:typename MyRefCarrier<p$2>::type m_$2; @]
bool operator==(const ParamState$1<dummy@[$2,1,$1:, p$2@]> &other)
{
return true
@[$2,1,$1: && m_$1 == other.m_$1@]
;
}
ParamState$1(@[$2,1,$1|, :p$2 a$2@]) @[$1!=0::@] @[$2,1,$1|, :m_$2(a$2)@]
{
}
ParamState$1<dummy@[$2,1,$1:, p$2@]> & operator() (int incrsteps)
{
@[$1!=0:int i;@]
@[$2,1,$1:
for (i = 0; i < incrsteps; ++i)
Increment<StripRef< p$2 >::type>::Incr(m_$2);
@]
return *this;
}
};
@[$1!=0:template<@[$2,1,$1|, :class p$2@]>@]
std::ostream& operator <<(std::ostream &os,const ParamState$1<0@[$2,1,$1:, p$2@]> &obj)
{
@[$1!=0:os@] @[$2,1,$1:<< obj.m_$2@];
return os;
}
@]
#define CAT2(a, b) a##b
#define CAT3(a, b, c) a##b##c
#define CAT4(a, b, c, d) a##b##c##d
// hook1: pre ignore
// hook2: pre supercede
// hook3: post ignore
// hook4: post supercede
@[$1,0,$a:
#define THGM_MAKE_TEST$1_void(id@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ParamState$1<0@[$2,1,$1:, param$2@] > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual void Func(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS(MRES_IGNORED, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META(MRES_IGNORED); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual void Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_NEWPARAMS(MRES_SUPERCEDE, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META(MRES_SUPERCEDE); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[$1+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[$1+1]; \
SourceHook::ProtoInfo protoinfo_##id = { $1, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_MAKE_TEST$1(id, ret_type@[$2,1,$1:, param$2@]) \
struct TestClass##id; \
typedef ParamState$1<0@[$2,1,$1:, param$2@] > ParamState_m##id; \
MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg2_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg3_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
MAKE_STATE_3(State_Deleg4_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \
\
struct TestClass##id \
{ \
static bool ms_DoRecall; \
\
virtual ret_type Func(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Func##id(this, ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
\
return 0; \
} \
\
struct Delegate1 : public MyDelegate \
{ \
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg1_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 1, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 1); \
} \
}; \
struct Delegate2 : public MyDelegate \
{ \
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg2_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 2, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 2); \
} \
}; \
struct Delegate3 : public MyDelegate \
{ \
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg3_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, 3, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META_VALUE(MRES_IGNORED, 3); \
} \
}; \
struct Delegate4 : public MyDelegate \
{ \
virtual ret_type Call(@[$2,1,$1|, :param$2 p$2@]) \
{ \
g_Inside_LeafFunc = true; \
ADD_STATE(State_Deleg4_##id(META_IFACEPTR(TestClass##id), PtrBuf(this), ParamState_m##id(@[$2,1,$1|, :p$2@]))); \
g_Inside_LeafFunc = false; \
if (ms_DoRecall) \
{ \
@[$2,1,$1:Increment<StripRef< param$2 >::type>::Incr(p$2);@] \
RETURN_META_VALUE_NEWPARAMS(MRES_SUPERCEDE, 4, &TestClass##id::Func, (@[$2,1,$1|, :p$2@])); \
} \
else \
RETURN_META_VALUE(MRES_SUPERCEDE, 4); \
}; \
}; \
}; \
\
bool TestClass##id::ms_DoRecall = false; \
\
SourceHook::PassInfo paraminfos_##id[$1+1]; \
SourceHook::PassInfo::V2Info paraminfos2_##id[$1+1]; \
SourceHook::ProtoInfo protoinfo_##id = { $1, {0, 0, 0}, paraminfos_##id, \
SourceHook::ProtoInfo::CallConv_ThisCall, __SH_EPI, paraminfos2_##id }; \
\
SourceHook::Impl::GenContext *g_Genc##id = NULL; \
CAutoPtrDestruction<SourceHook::Impl::GenContext> g_Genc_ad##id(NULL);
#define THGM_SETUP_PI$1(id@[$2,1,$1:, p$2_type, p$2_passtype, p$2_flags@]) \
void setuppi_##id() \
{ \
paraminfos_##id[0].size = 1; paraminfos_##id[0].type = 0; paraminfos_##id[0].flags = 0; \
\
@[$2,1,$1: paraminfos_##id[$2].size = sizeof(p$2_type); paraminfos_##id[$2].type = p$2_passtype; paraminfos_##id[$2].flags = p$2_flags; @] \
\
@[$2,1,$1: paraminfos2_##id[$2].pNormalCtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::NormalConstructor) : NULL; @] \
@[$2,1,$1: paraminfos2_##id[$2].pCopyCtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::CopyConstructor) : NULL; @] \
@[$2,1,$1: paraminfos2_##id[$2].pDtor = (paraminfos_##id[$2].flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< p$2_type >::type>::Destructor) : NULL; @] \
}
@]
#define THGM_SETUP_RI(id, ret_type, ret_passtype, ret_flags) \
void setupri_##id() \
{ \
protoinfo_##id.retPassInfo.size = sizeof(ret_type); \
protoinfo_##id.retPassInfo.type = ret_passtype; \
protoinfo_##id.retPassInfo.flags = ret_flags; \
\
protoinfo_##id.retPassInfo2.pNormalCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_OCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::NormalConstructor) : NULL; \
protoinfo_##id.retPassInfo2.pCopyCtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_CCtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::CopyConstructor) : NULL; \
protoinfo_##id.retPassInfo2.pDtor = (protoinfo_##id.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ODtor) ? FindFuncAddr(&Ctor_Thunk<StripRef< ret_type >::type>::Destructor) : NULL; \
}
#define THGM_ADD_HOOK(id, num) \
CAT4(hook, num, _, id) = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pTest##id), \
0, myhookman##id, PtrBufPtr(new TestClass##id::Delegate##num), num >= 3);
#define THGM_REMOVE_HOOK(id, num) \
g_SHPtr->RemoveHookByID(CAT4(hook, num, _, id));
#define THGM_CALLS_void(id, call_params) \
pTest##id->Func call_params; \
SH_CALL(pTest##id, &TestClass##id::Func) call_params;
#define THGM_DO_TEST_void(id, call_params) \
setuppi_##id(); \
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
g_Genc_ad##id.set(g_Genc##id); \
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - no hooks */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part2"); \
THGM_REMOVE_HOOK(id, 1); \
\
/* no hooks - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part3"); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 2); \
THGM_REMOVE_HOOK(id, 3); \
/* hook1, hook2 - hook3, hook4 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS_void(id, call_params); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);
#define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \
CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \
CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall");
#define THGM_DO_TEST(id, call_params) \
setuppi_##id(); \
setupri_##id(); \
g_Genc##id = new SourceHook::Impl::GenContext(&protoinfo_##id, 0, 0, g_SHPtr); \
g_Genc_ad##id.set(g_Genc##id); \
SourceHook::HookManagerPubFunc myhookman##id = g_Genc##id->Generate(); \
int hook1_##id, hook2_##id, hook3_##id, hook4_##id; \
\
TestClass##id::ms_DoRecall = false; \
TestClass##id *pTest##id = new TestClass##id; \
CAutoPtrDestruction<TestClass##id> apd##id(pTest##id); \
\
/* no hooks - no hooks */ \
PtrBuf_Clear(); \
THGM_CALLS(id, call_params, 0, 0, "Part1"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part1"); \
\
/* hook1 - no hooks */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_CALLS(id, call_params, 0, 0, "Part2"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part2"); \
THGM_REMOVE_HOOK(id, 1); \
\
/* no hooks - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part3"); \
CHECK_STATES((&g_States, \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part3"); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 0, 0, "Part4"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part4"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
\
/* hook1, hook2 - hook3 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_CALLS(id, call_params, 2, 0, "Part5"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part5"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 2); \
THGM_REMOVE_HOOK(id, 3); \
/* hook1, hook2 - hook3, hook4 */ \
PtrBuf_Clear(); \
THGM_ADD_HOOK(id, 1); \
THGM_ADD_HOOK(id, 2); \
THGM_ADD_HOOK(id, 3); \
THGM_ADD_HOOK(id, 4); \
THGM_CALLS(id, call_params, 4, 0, "Part6"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params), \
new State_Deleg2_##id(pTest##id, 1, ParamState_m##id call_params), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params), \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part6"); \
\
/* hook1 - hook3, hook4, with recalls! */ \
\
TestClass##id::ms_DoRecall = true; \
THGM_REMOVE_HOOK(id, 2); \
THGM_CALLS(id, call_params, 4, 0, "Part7"); \
CHECK_STATES((&g_States, \
new State_Deleg1_##id(pTest##id, 0, ParamState_m##id call_params(0)), \
new State_Func##id(pTest##id, ParamState_m##id call_params(1)), \
new State_Deleg3_##id(pTest##id, 2, ParamState_m##id call_params(1)), \
new State_Deleg4_##id(pTest##id, 3, ParamState_m##id call_params(2)), \
/* sh_call one */ \
new State_Func##id(pTest##id, ParamState_m##id call_params), \
NULL), "Test" #id " Part7"); \
THGM_REMOVE_HOOK(id, 1); \
THGM_REMOVE_HOOK(id, 3); \
THGM_REMOVE_HOOK(id, 4);