
Classes | |
| struct | CallParams |
Enumerations | |
| enum | { PARAM_TYPE_MASK = 0x5, INT_PARAM = 0, REAL_PARAM = 1, REF_PARAM = 4, STR_PARAM = 5, ENDIAN_SWAP_SC = 1, DO_ENDIAN_SWAP = 1 << ENDIAN_SWAP_SC, RESERVED_BITS = 0xf8 } |
Functions | |
| unsigned int | BuildStack (char *stack) |
| template<class P1 , class P2 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, bool es1=true, bool es2=true) |
| template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true) |
| template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 , class P7 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true, bool es7=true) |
| template<class P1 , class P2 , class P3 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, bool es1=true, bool es2=true, bool es3=true) |
| template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 , class P7 , class P8 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true, bool es6=true, bool es7=true, bool es8=true) |
| template<class P1 > | |
| unsigned int | BuildStack (char *stack, P1 p1, bool es1=true) |
| template<class P1 , class P2 , class P3 , class P4 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, P4 p4, bool es1=true, bool es2=true, bool es3=true, bool es4=true) |
| template<class P1 , class P2 , class P3 , class P4 , class P5 > | |
| unsigned int | BuildStack (char *stack, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, bool es1=true, bool es2=true, bool es3=true, bool es4=true, bool es5=true) |
| bool | CallWithStack (CallParams &call, void *functionPtr) |
| template<class item > | |
| size_t | D_size (item const ) |
| template<class item > | |
| size_t | D_size (item const *const ) |
| template<class item > | |
| size_t | D_size (item *const ) |
| size_t | D_size (char *const str) |
| size_t | D_size (char const *const str) |
| template<class item > | |
| unsigned | D_type (item const ) |
| unsigned | D_type (char *const ) |
| unsigned | D_type (long double) |
| unsigned | D_type (double) |
| unsigned | D_type (const char *const ) |
| template<class item > | |
| unsigned | D_type (item const *const ) |
| template<class item > | |
| unsigned | D_type (item *const ) |
| unsigned | D_type (float) |
| bool | DeserializeParametersAndBuildCall (CallParams &call, char *in, unsigned int inLength, void *lastParam, void *thisPtr) |
| Given a stack, the length of the stack, a possible last parameter, and a possible this pointer, build a call to a C or C++ function. | |
| template<class item > | |
| void | Push (char *&p, item const *const i, bool doEndianSwap) |
| void | Push (char *&p, char *const i, bool doEndianSwap) |
| void | Push (char *&p, const char *const i, bool doEndianSwap) |
| template<class item > | |
| void | Push (char *&p, item const i, bool doEndianSwap) |
| template<class item > | |
| void | Push (char *&p, item *const i, bool doEndianSwap) |
| template<class item > | |
| void | PushHeader (char *&p, item const i, bool endianSwap) |
| void | SerializeHeader (char *&out, unsigned int numParams) |
| anonymous enum |
| PARAM_TYPE_MASK | |
| INT_PARAM | |
| REAL_PARAM | |
| REF_PARAM | |
| STR_PARAM | |
| ENDIAN_SWAP_SC | |
| DO_ENDIAN_SWAP | |
| RESERVED_BITS |
Definition at line 709 of file Gen_RPC8.h.
{
// to maintain binary compatibility with a historical decision, bit 1 is not used
// in defining the "well known param" types
PARAM_TYPE_MASK = 0x5,
INT_PARAM = 0, // pass by value an integer or structure composed of integers.
REAL_PARAM = 1, // pass by value a SINGLE floating point parameter.
REF_PARAM = 4, // pass a pointer or reference to data which must be aligned.
STR_PARAM = 5, // pass a pointer to this data, which need not be unaligned;
// but MUST be null terminated.
// OBJECT_PARAM = 8, // TODO: pass by value an object, object id as first uint32_t of serialized data?
// OBJECT_REF_PARAM = 9, // TODO: pass by reference an object, object id as first uint32_t of serialized data?
// SC == "Shift count" (Bit index); which is always useful.
ENDIAN_SWAP_SC = 1, DO_ENDIAN_SWAP = 1 << ENDIAN_SWAP_SC,
RESERVED_BITS = 0xf8,
};
| unsigned int GenRPC::BuildStack | ( | char * | stack | ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 3 of file Gen_RPC8.cpp.
References SerializeHeader().
Referenced by RakNet::AutoRPC::Call(), and RakNet::AutoRPC::CallExplicit().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 0);
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| bool | es1 = true, |
|||
| bool | es2 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 465 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 2);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| P4 | p4, | |||
| P5 | p5, | |||
| P6 | p6, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true, |
|||
| bool | es4 = true, |
|||
| bool | es5 = true, |
|||
| bool | es6 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 537 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 6);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| P4 | p4, | |||
| P5 | p5, | |||
| P6 | p6, | |||
| P7 | p7, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true, |
|||
| bool | es4 = true, |
|||
| bool | es5 = true, |
|||
| bool | es6 = true, |
|||
| bool | es7 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 560 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 7);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
PushHeader(stackPtr, p7, es7);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
Push( stackPtr, p7, es7 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 480 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 3);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| P4 | p4, | |||
| P5 | p5, | |||
| P6 | p6, | |||
| P7 | p7, | |||
| P8 | p8, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true, |
|||
| bool | es4 = true, |
|||
| bool | es5 = true, |
|||
| bool | es6 = true, |
|||
| bool | es7 = true, |
|||
| bool | es8 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 585 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 8);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
PushHeader(stackPtr, p6, es6);
PushHeader(stackPtr, p7, es7);
PushHeader(stackPtr, p8, es8);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
Push( stackPtr, p6, es6 );
Push( stackPtr, p7, es7 );
Push( stackPtr, p8, es8 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| bool | es1 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 452 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 1);
PushHeader(stackPtr, p1, es1);
Push( stackPtr, p1, es1 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| P4 | p4, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true, |
|||
| bool | es4 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 497 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 4);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
return (unsigned int)(stackPtr-stack);
}
| unsigned int GenRPC::BuildStack | ( | char * | stack, | |
| P1 | p1, | |||
| P2 | p2, | |||
| P3 | p3, | |||
| P4 | p4, | |||
| P5 | p5, | |||
| bool | es1 = true, |
|||
| bool | es2 = true, |
|||
| bool | es3 = true, |
|||
| bool | es4 = true, |
|||
| bool | es5 = true | |||
| ) |
Builds up a function call and all parameters onto a stack
| [out] | Destination | stack, which must be big enough to hold all parameters |
Definition at line 516 of file Gen_RPC8.h.
References Push(), PushHeader(), and SerializeHeader().
{
char *stackPtr = (char*) stack;
SerializeHeader(stackPtr, 5);
PushHeader(stackPtr, p1, es1);
PushHeader(stackPtr, p2, es2);
PushHeader(stackPtr, p3, es3);
PushHeader(stackPtr, p4, es4);
PushHeader(stackPtr, p5, es5);
Push( stackPtr, p1, es1 );
Push( stackPtr, p2, es2 );
Push( stackPtr, p3, es3 );
Push( stackPtr, p4, es4 );
Push( stackPtr, p5, es5 );
return (unsigned int)(stackPtr-stack);
}
| bool GenRPC::CallWithStack | ( | CallParams & | call, | |
| void * | functionPtr | |||
| ) |
Definition at line 335 of file Gen_RPC8.cpp.
References AUTO_RPC_CALLSPEC, AUTO_RPC_INT_ARGS_12, AUTO_RPC_INT_ARGS_3, AUTO_RPC_INT_ARGS_32, AUTO_RPC_INT_ARGS_4_64, AUTO_RPC_INT_ARGS_6, AUTO_RPC_INT_ARGS_64, and AUTO_RPC_INT_ARGS_9.
Referenced by RakNet::AutoRPC::OnAutoRPCCall().
{
#if AUTO_RPC_ABI
// Are we x86-32?
#if !defined( AUTO_RPC_NO_ASM ) && ( defined(__i386__) || defined( _M_IX86 ) || defined( __INTEL__ ) )
#if !defined(__GNUC__)
// Intel dialect assembly
NaturalWord const paramc = call.numIntParams;
#pragma warning(disable:4311) // pointer truncation
NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
_asm
{
// Load numbytes.
mov ecx, paramc
// allocate space on the stack for all these params
lea edi,dword ptr[ecx * 4]
sub esp,edi
// setup source of copy
mov esi, paramv
// Setup the destination of the copy: the return stack.
mov edi,esp
// copy data
rep movs dword ptr es:[edi],dword ptr [esi]
// call the function
call functionPtr
// Restore the stack to its state, prior to our invocation.
//
// Detail: edi is one of the registers that must be preserved
// across function calls. (The compiler should be saving it for us.)
//
// We left edi pointing to the end of the block copied; i.e. the state
// of the stack prior to copying our params. So by loading it
// into the esp we can restore the return stack to the state prior
// to the copy.
//
mov esp,edi
};
#else
// GCC has its own form of asm block - so we'll always have to write two versions.
// Therefore, as we're writing it twice, we use the ATT dialect, because only later
// gcc support Intel dialect. This one also aligns the stack to a multiple of 16 bytes; which
// windows doesn't seem to care about.
// Be aware, we can't use offset of to get the address, as gcc insists on sticking.
// NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
asm (\
"lea 4(%%ecx),%%esi\n\
mov (%%ecx),%%ecx\n\
lea (,%%ecx,4),%%edi\n\
sub %%edi,%%esp\n\
mov $12,%%edx\n\
and %%esp,%%edx\n\
sub %%edx,%%esp\n\
mov %%esp,%%edi\n\
rep movsl %%ds:(%%esi),%%es:(%%edi)\n\
add %%edx,%%edi\n\
call *%1\n\
mov %%edi,%%esp"\
: /* no outputs */\
: "c" ( &call ), "m" (functionPtr)\
: "%edi" , "%esi", "%edx", "%eax"\
);
#endif // GNUC vs non GNUC
return 1;
#elif !defined( AUTO_RPC_NO_ASM ) && ( defined( _M_X64 ) || defined( __x86_64__ ) || defined( _M_AMD64 ) )
#if AUTO_RPC_ABI == AUTO_RPC_ABI_WIN_AMD64
NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
_asm {
// rcx := number of qwords to copy
mov rcx, paramc
// r9 := 0
sub r9,r9
// rsi => our parameter list.
mov rsi, paramv
// r9 := -(number of qwords to copy)
sub r9,rcx
// Preparation to align the stack to 16 byte boundary
mov rdx,8
// rdi => projected bottom of stack
lea rdi,dword ptr[rsp + r9 * 8]
// figure out if stack needs aligning
and rdx,rdi
// save stack into rbx
mov rbx,rsp
// align stack
sub rdi,rdx
mov rsp,rdi
// rdx => our parameter list
mov rdx,rsi
//
// copy data - we copy all parameters, because we have to
// create a shadow area; and this way its easiest.
//
rep movs qword ptr es:[edi],qword ptr [esi]
// load registers
// rcx|xmm0, rdx|xmm1,r8|xmm2,r9|xmm3
mov rcx,qword ptr [rdx]
mov r8,qword ptr 16[rdx]
movq xmm0,rcx
mov r9,qword ptr 24[rdx]
movq xmm2,r8
mov rdx,qword ptr 8[rdx]
movq xmm3,r9
movq xmm1,rdx
// call the function
call functionPtr
// Restore the stack to its state, prior to our invocation -
// saved in rbx.
mov rsp,rbx
}
#elif AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
//
// GCC won't generate a stack frame on higher optimization levels, so we don't touch it.
// on -O3 it inlines the code, breaking it because of the jump reference.
//
// I figure a 64-bit compiler will be recent enough to do Intel syntax. May need to change
// my mind on that. NB. Structure members are hard coded into this.
//
asm (\
".intel_syntax noprefix\n\
push rbx\n\
mov rax,rsi\n\
push r15\n\
mov ecx,dword ptr[rdi+8+8*8]\n\
lea rsi,[rdi+8+8*8+8]\n\
mov r15,rsp\n\
lea rbx,[rdi+8]\n\
sub r8,r8\n\
sub rcx,6\n\
lea r9,[rsi + 6 * 8]\n\
jbe .L1\n\
sub r8,rcx\n\
mov rdx,8\n\
lea rdi,qword ptr[rsp + r8 * 8]\n\
and rdx,rdi\n\
mov rsi,r9\n\
sub rdi,rdx\n\
mov rsp,rdi\n\
rep movsq \n\
.L1:\n\
movq xmm0,[rbx]\n\
movq xmm1,[rbx+8]\n\
movq xmm2,[rbx+16]\n\
movq xmm3,[rbx+24]\n\
movq xmm4,[rbx+32]\n\
movq xmm5,[rbx+40]\n\
movq xmm6,[rbx+48]\n\
movq xmm7,[rbx+56]\n\
mov rdi,[r9-48]\n\
mov rsi,[r9-40]\n\
mov rdx,[r9-32]\n\
mov rcx,[r9-24]\n\
mov r8,[r9-16]\n\
mov r9,[r9-8]\n\
call rax\n\
mov rsp,r15\n\
pop r15\n\
pop rbx\n\
.att_syntax prefix"\
: /* no outputs */\
: "D" ( &call ), "S" (functionPtr)\
: "%rdx", "%rcx" , "%r8", "%r9", "%rax",\
"%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" );
// : "D", ( &call ), "c" ( &call.numIntParams ), "S" ( paramv ), "b" ( floatv ), "a" (functionPtr)
#else
#error unsupport ABI
#endif
return 1;
#else
// AUTO_RPC_NO_ASM or no x86-32/x86-64
//
// 4. Passing the parameters.
//
// The compiler knows how to call functions, so having sorted out the argument list,
// we just pass it to a function of the correct form - and let the compiler align stacks,
// load registers, place parameters where they should be.
//
// This is particularly important as GCC has control over the stack frame, and it can
// improperly frame it - for instance utilising red zones to save args, rather than pushing them.
// On PowerPC it must create the parameter passing area, too.
//
// The most brute force way, is to code a function call for every possible number of parameters
//
// switch( paramc ) {
// case 1: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord)) myfunc)( callParam[0] ); break;
// case 2: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1] ); break;
// ...
// case 64: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1], ... , callParam[63] ); break;
// }
//
// This is the only way to code WIN32 stdcall, for example, as the args must match exactly;
// and so the only way to call from C if you need to call WINAPI routines.
//
// 2) Fortunately most calling conventions allowing excessive args. So this means we could
// write something like below:
//
// ( (void(*)(...)) myfunc )( args[0],...,args[63] );
//
// And although this should work, its a huge performance penalty copying between memory
// locations for so many args.
//
// So we compromise - and do a stepped sequence. Noticing that the WIN64 ABI alwys requires
// space for three args anyway.
//
// And on SysV x64 systems, the first 6 args are passed in reg; so again, these are only
// copies into register, not memory copies. And finally that if we load word[n], word[n+1]
// is loaded into the cache - thus the overhead for loading is not as big as it might be.
//
// For most realistic cases, a dozen args would be excessive. Obviously, if you have
// a tested assembler equivalent, its probably better to use that.
//
//
#if AUTO_RPC_FLOAT_REG_PARAMS
if ( call.numRealParams == 0 )
#endif
{
if ( call.numIntParams <= 3 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_3)) functionPtr )( AUTO_RPC_INT_ARGS_3( call ) );
return 1;
}
if ( call.numIntParams <= 6 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_6)) functionPtr )( AUTO_RPC_INT_ARGS_6( call ) );
return 1;
}
if ( call.numIntParams <= 9 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_9))functionPtr)( AUTO_RPC_INT_ARGS_9( call ) );
return 1;
}
if ( call.numIntParams <= 12 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_12))functionPtr)( AUTO_RPC_INT_ARGS_12( call ) );
return 1;
}
if ( call.numIntParams <= 32 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_32))functionPtr)( AUTO_RPC_INT_ARGS_32( call ) );
return 1;
}
if ( call.numIntParams <= 64 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_64))functionPtr)( AUTO_RPC_INT_ARGS_64( call ) );
return 1;
}
}
#if AUTO_RPC_FLOAT_REG_PARAMS && !AUTO_RPC_ALLOC_SEPARATE_FLOATS
else
{
if ( call.numIntParams > 64 ) return 0;
switch( call.realMap )
{
// case 0: - no floats, never happens here.
case 1: ( (void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 2:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 3:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 4: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 5:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 6:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 7:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 8: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 9:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 10:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 11:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 12: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 13:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 14:
((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.intParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
case 15:
((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
call.realParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
AUTO_RPC_INT_ARGS_4_64( call )
);
break;
default: return 0;
}
}
#elif AUTO_RPC_FLOAT_REG_PARAMS
else
{
// we pass FLOAT args last for powerpc compatibility. And although it means we pass them twice,
// they should end up in the correct floating point register, with the rest of the integers in the
// correct place...
//
// NB if you want to write inline asm for powerpc, you'll have to be put it in a separate
// "naked" function to that uou can setup the parameter passing area and ensure its big enough.
// (GCC will delete functions that are unused - it will delete the body of functions that
// aren't called.)
//
if ( call.numIntParams <= 3 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_3,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_3( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 6 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_6,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_6( call ),AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 9 )
{
((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_9,AUTO_RPC_FLOAT_REG_TYPE))functionPtr)( AUTO_RPC_INT_ARGS_9( call ),AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 12 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_12,AUTO_RPC_FLOAT_REG_TYPE)) functionPtr )( AUTO_RPC_INT_ARGS_12( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
if ( call.numIntParams <= 64 )
{
( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_64,AUTO_RPC_FLOAT_REG_TYPE)) functionPtr )( AUTO_RPC_INT_ARGS_64( call ), AUTO_RPC_FLOAT_REG_ARGS( call ) );
return 1;
}
}
#endif // AUTO_RPC_FLOAT_REG_PARAMS
return 0;
#endif // AUTO_RPC_NO_ASM
#else // AUTO_RPC_ABI
return 0;
#endif
}
| size_t GenRPC::D_size | ( | item | const | ) |
| size_t GenRPC::D_size | ( | item const * | const | ) |
Definition at line 696 of file Gen_RPC8.h.
{ return sizeof( item ); }
| size_t GenRPC::D_size | ( | item * | const | ) |
Definition at line 701 of file Gen_RPC8.h.
{ return sizeof( item ); }
| size_t GenRPC::D_size | ( | char *const | str | ) |
Definition at line 38 of file Gen_RPC8.cpp.
{ return strlen( str ) + 1; }
| size_t GenRPC::D_size | ( | char const *const | str | ) |
Definition at line 40 of file Gen_RPC8.cpp.
{ return strlen( str ) + 1; }
| unsigned GenRPC::D_type | ( | item | const | ) |
| unsigned GenRPC::D_type | ( | char * const | ) |
Definition at line 28 of file Gen_RPC8.cpp.
{ return STR_PARAM; }
| unsigned GenRPC::D_type | ( | long | double | ) |
Definition at line 35 of file Gen_RPC8.cpp.
{ return REAL_PARAM; }
| unsigned GenRPC::D_type | ( | double | ) |
Definition at line 33 of file Gen_RPC8.cpp.
{ return REAL_PARAM; }
| unsigned GenRPC::D_type | ( | const char * const | ) |
Definition at line 26 of file Gen_RPC8.cpp.
{ return STR_PARAM; }
| unsigned GenRPC::D_type | ( | item const * | const | ) |
Definition at line 732 of file Gen_RPC8.h.
{ return REF_PARAM; }
| unsigned GenRPC::D_type | ( | item * | const | ) |
Definition at line 736 of file Gen_RPC8.h.
{ return REF_PARAM; }
| unsigned GenRPC::D_type | ( | float | ) |
Definition at line 31 of file Gen_RPC8.cpp.
{ return REAL_PARAM; }
| bool GenRPC::DeserializeParametersAndBuildCall | ( | CallParams & | call, | |
| char * | in, | |||
| unsigned int | inLength, | |||
| void * | lastParam, | |||
| void * | thisPtr | |||
| ) |
Definition at line 64 of file Gen_RPC8.cpp.
References AUTO_RPC__ALIGN_P2, AUTO_RPC_ALIGN_P2, AUTO_RPC_ARRAY_END, AUTO_RPC_REF_ALIGN, DO_ENDIAN_SWAP, PARAM_TYPE_MASK, REAL_PARAM, REF_PARAM, RESERVED_BITS, RakNet::BitStream::ReverseBytesInPlace(), and STR_PARAM.
Referenced by RakNet::AutoRPC::OnAutoRPCCall().
{
#if AUTO_RPC_ABI
NaturalWord *intCallParam = call.intParams;
char *refParam = call.refParams;
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
HardwareReal *realCallParam = call.realParams;
#endif
#if AUTO_RPC_CREATE_FLOAT_MAP
call.realMap = 0;
call.numRealParams = 0;
#endif
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// large structure parameters have to be bumped up here - which corresponds with the start
// of the parameters that *are* passed on the stack.
NaturalWord *memParam = &call.intParams[ AUTO_RPC_INT_REG_PARAMS ];
#endif
// this is first arg - assume space ;-)
#pragma warning(disable:4311) // pointer truncation
if ( thisPtr )
*(intCallParam++) = reinterpret_cast<NaturalWord>( thisPtr );
unsigned int serializedArgs = *(unsigned char*)in;
unsigned char* header = (unsigned char*)in + 1;
unsigned char* data = &header[ serializedArgs * ( sizeof( unsigned int ) + 1 ) ];
// check we have the entire header in buffer
if ( data > (unsigned char*) &in[ inLength ] )
return 0;
for ( unsigned int i = 0; i < serializedArgs; i++ )
{
// read header entry
int plen = *(unsigned int*)header;
header += sizeof( unsigned int );
unsigned char const flags = *( header++ );
// Some bits are not used by the current implementation. So if we find them we bail because
// we clearly are not equipped to handle the data - and is there no safe way to "fail".
if ( flags & RESERVED_BITS )
return 0;
#ifndef __BITSTREAM_NATIVE_END
if (flags & DO_ENDIAN_SWAP)
{
RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)&plen , sizeof( plen ) );
}
#endif
if ( !plen || data + plen > (unsigned char*)&in[ inLength ] )
return 0;
// handle null-terminated strings.
if ( ( flags & PARAM_TYPE_MASK ) == STR_PARAM )
{
if ( intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
// Check this has some sort of null termination. NB this assumes string is genuine Ascii
// or UTF+8; using unicode (ie. UTF+16, UCS) could break this.
if ( data[ plen - 1 ] != 0 )
return 0;
// The string doesn't need to be aligned, so we leave it in place; saving a copy, and
// preventing clogging up of our buffers with data.
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord>( data );
data += plen;
continue;
}
#ifndef __BITSTREAM_NATIVE_END
if (flags & DO_ENDIAN_SWAP)
{
RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)data , plen );
}
#endif
// convert pointer to ref.
if ( ( flags & PARAM_TYPE_MASK ) == REF_PARAM
#if AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
|| plen > AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
#endif
)
{
char *nextRefParam = refParam + AUTO_RPC__ALIGN_P2( plen, AUTO_RPC_REF_ALIGN );
if ( nextRefParam >= AUTO_RPC_ARRAY_END( call.refParams ) || intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
memcpy( refParam, data, plen );
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord>( refParam );
refParam = nextRefParam;
data += plen;
continue;
}
// Guarantee we have space on the output stack to accommodate the parameter.
NaturalWord *nextParam = (NaturalWord*)( (char*)intCallParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
if ( nextParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
#if AUTO_RPC_ALLOC_SEPARATE_FLOATS
if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM
// long doubles, of various sizes (10, 16), all get passed on the stack
&& (size_t) plen <= sizeof(double)
// once we've allocated all our floats, they get treated as ordinary int params
&& realCallParam < AUTO_RPC_ARRAY_END( call.realParams )
)
{
if ( plen != sizeof( float ) && plen != sizeof( double ) ) {
printf("illegal float size %d\n", plen );
// We can't handle it - it's not a real real :lol:
return 0;
}
#ifdef __BIG_ENDIAN__
memcpy( (char*)( realCallParam + 1 ) - plen, data, plen );
#else
memcpy( (char*)realCallParam, data, plen );
#endif
#if !AUTO_RPC_INT_SHADOW_OF_FLOATS
// we didn't use the int slot, so don't allow an advance.
nextParam = intCallParam;
#endif
// next time, we use the next Real slot
realCallParam++;
}
#if !AUTO_RPC_INT_SHADOW_OF_FLOATS
else
#endif
#endif // AUTO_RPC_ALLOC_SEPARATE_FLOATS
{
// the processor can atomically zero-extend small types, so even with the test,
// it should be faster than memcpy+memset.
if ( plen == 1 )
*intCallParam = *(uint8_t*)data; // should resolve to movzx and a move
else if ( plen == 2 )
*intCallParam = *(uint16_t*)data; // if network order replace use htons(), and skip EndianSwap()
else if ( plen == 4 )
*intCallParam = *(uint32_t*)data; // if network order replace use htonl(), and skip EndianSwap()
#if AUTO_RPC_AUTORPC_WORD == 64
else if ( plen == 8 )
*intCallParam = *(uint64_t*)data;
#endif
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
//
// SYSV ABI: aggregates greater 16 bytes must go on the stack;
// in practice, that means they can't come below AUTO_RPC_INT_REG_PARAMS when we call a function.
//
else if ( plen > 16 || ( plen > 8 && intCallParam == &call.intParams[ AUTO_RPC_INT_REG_PARAMS - 1] ) || ( flags & REAL_PARAM ) )
{
if ( intCallParam < memParam )
{
NaturalWord*const nextMemParam = (NaturalWord*)( (char*)memParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
if ( nextMemParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
memcpy( memParam, data, plen );
// prevent advancing the ptr slot, since we didn't use it.
nextParam = intCallParam;
// but advance the memparam
memParam = nextMemParam;
}
else
{
memcpy( (void*)intCallParam, data, plen );
}
}
#endif // AUTO_RPC_ABI_SYSV_AMD64
else
{
// We don't need to worry about alignment, because any type that's not a whole multiple
// of the natual word size will be an aggregate and that should be at the base of memory -
// this is true for some PowerPC systems (see [e]) but not all. But hey, you
// probably should be passing such structs by reference.
//
// Zeroing is also unecessary as code shouldn't be reading beyodn the bounds of the structure.
//
memcpy( (void*)intCallParam, data, plen );
}
}
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// skip over any stored "class MEMORY" (see [b]) parameters.
if ( nextParam == &call.intParams[AUTO_RPC_INT_REG_PARAMS] )
intCallParam = memParam;
else
#endif
// advance to next output param
intCallParam = nextParam;
#if !AUTO_RPC_ALLOC_SEPARATE_FLOATS && AUTO_RPC_CREATE_FLOAT_MAP
if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM && i < AUTO_RPC_FLOAT_REG_PARAMS && ( plen == sizeof( double ) || plen == sizeof( float ) ) )
{
call.numRealParams++;
call.realMap |= ( 1 << i );
}
#endif
// advance to next input arg.
data += plen;
}
// space for lastParam?
if ( &intCallParam[1] >= AUTO_RPC_ARRAY_END( call.intParams ) )
return 0;
#pragma warning(disable:4311) // pointer truncation
*( intCallParam++ ) = reinterpret_cast<NaturalWord >( lastParam );
#if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
// figure out how many args we have notched up.
if ( memParam > &call.intParams[AUTO_RPC_INT_REG_PARAMS] && memParam > intCallParam )
intCallParam = memParam;
#endif
// convert from ptrdif_t to unsigned int; should be small enough, even if its 64-bit pointers.
call.numIntParams = ( unsigned int )( intCallParam - call.intParams );
#if AUTO_RPC_FLOAT_REG_PARAMS && AUTO_RPC_ALLOC_SEPARATE_FLOATS
call.numRealParams = ( unsigned int )( realCallParam - call.realParams );
#endif
return 1;
#else // AUTO_RPC_ABI
return 0;
#endif
}
| void GenRPC::Push | ( | char *& | p, | |
| item const *const | i, | |||
| bool | doEndianSwap | |||
| ) |
Definition at line 629 of file Gen_RPC8.h.
References RakNet::BitStream::DoEndianSwap(), and RakNet::BitStream::ReverseBytesInPlace().
{
memcpy( (void*)p, (void*)i, sizeof( *i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( *i );
}
| void GenRPC::Push | ( | char *& | p, | |
| char *const | i, | |||
| bool | doEndianSwap | |||
| ) |
Definition at line 11 of file Gen_RPC8.cpp.
| void GenRPC::Push | ( | char *& | p, | |
| const char *const | i, | |||
| bool | doEndianSwap | |||
| ) |
Definition at line 19 of file Gen_RPC8.cpp.
| void GenRPC::Push | ( | char *& | p, | |
| item const | i, | |||
| bool | doEndianSwap | |||
| ) |
Definition at line 611 of file Gen_RPC8.h.
References RakNet::BitStream::DoEndianSwap(), and RakNet::BitStream::ReverseBytesInPlace().
Referenced by BuildStack(), and PushHeader().
{
memcpy( (void*)p, (void*)&i, sizeof( i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( i );
}
| void GenRPC::Push | ( | char *& | p, | |
| item *const | i, | |||
| bool | doEndianSwap | |||
| ) |
Definition at line 620 of file Gen_RPC8.h.
References RakNet::BitStream::DoEndianSwap(), and RakNet::BitStream::ReverseBytesInPlace().
{
memcpy( (void*)p, (void*)i, sizeof( *i ) );
if (doEndianSwap && RakNet::BitStream::DoEndianSwap())
RakNet::BitStream::ReverseBytesInPlace((unsigned char*) p,sizeof( i ));
p += sizeof( *i );
}
| void GenRPC::PushHeader | ( | char *& | p, | |
| item const | i, | |||
| bool | endianSwap | |||
| ) |
| void GenRPC::SerializeHeader | ( | char *& | out, | |
| unsigned int | numParams | |||
| ) |
Definition at line 42 of file Gen_RPC8.cpp.
Referenced by BuildStack().
{
*out = (char) numParams;
out++;
//out[*writeOffset]=(char) numParams;
//*writeOffset+=sizeof(unsigned char);
}
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.