Shadowrun: Awakened
Classes | Enumerations | Functions

GenRPC Namespace Reference

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)

Enumeration Type Documentation

anonymous enum
Enumerator:
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,
};


Function Documentation

unsigned int GenRPC::BuildStack ( char *  stack  ) 

Builds up a function call and all parameters onto a stack

Parameters:
[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);
}

template<class P1 , class P2 >
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

Parameters:
[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);
}

template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 >
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

Parameters:
[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);
}

template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 , class P7 >
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

Parameters:
[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);
}

template<class P1 , class P2 , class P3 >
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

Parameters:
[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);
}

template<class P1 , class P2 , class P3 , class P4 , class P5 , class P6 , class P7 , class P8 >
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

Parameters:
[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);
}

template<class P1 >
unsigned int GenRPC::BuildStack ( char *  stack,
P1  p1,
bool  es1 = true 
)

Builds up a function call and all parameters onto a stack

Parameters:
[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);
}

template<class P1 , class P2 , class P3 , class P4 >
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

Parameters:
[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);
}

template<class P1 , class P2 , class P3 , class P4 , class P5 >
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

Parameters:
[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
}

template<class item >
size_t GenRPC::D_size ( item  const  ) 

Definition at line 691 of file Gen_RPC8.h.

Referenced by PushHeader().

{ return sizeof( item ); }

template<class item >
size_t GenRPC::D_size ( item const *  const  ) 

Definition at line 696 of file Gen_RPC8.h.

{ return sizeof( item ); }

template<class 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; }

template<class item >
unsigned GenRPC::D_type ( item  const  ) 

Definition at line 728 of file Gen_RPC8.h.

Referenced by PushHeader().

{ return INT_PARAM; }

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; }

template<class item >
unsigned GenRPC::D_type ( item const *  const  ) 

Definition at line 732 of file Gen_RPC8.h.

{ return REF_PARAM; }

template<class item >
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

}

template<class item >
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) doEndianSwap;
    size_t len = strlen( i ) + 1;
    memcpy( (void*)p, i, len );
    p += len;
}

void GenRPC::Push ( char *&  p,
const char *const   i,
bool  doEndianSwap 
)

Definition at line 19 of file Gen_RPC8.cpp.

                                                                   {
    (void) doEndianSwap;
    size_t len = strlen( i ) + 1;       
    memcpy( (void*)p, i, len );
    p += len;
}

template<class item >
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 );
}

template<class item >
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 );
}

template<class item >
void GenRPC::PushHeader ( char *&  p,
item const   i,
bool  endianSwap 
)

Definition at line 752 of file Gen_RPC8.h.

References D_size(), D_type(), and Push().

Referenced by BuildStack().

                                                           {
    unsigned int   s = (unsigned int) D_size( i );
    unsigned char  f = D_type( i ) | ( ((int) endianSwap) << ENDIAN_SWAP_SC );
    Push( p, s, endianSwap );
    Push( p, f, false );
}

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.

GNU Lesser General Public License 3 Sourceforge.net