• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Gen_RPC8.cpp

Go to the documentation of this file.
00001 #include "Gen_RPC8.h"
00002 
00003 unsigned int GenRPC::BuildStack(char *stack)
00004 {
00005         char *stackPtr = (char*) stack;
00006         SerializeHeader(stackPtr, 0);
00007         return (unsigned int)(stackPtr-stack);
00008 }
00009 
00011 void GenRPC::Push( char*& p, char*const i, bool doEndianSwap) {
00012         (void) doEndianSwap;
00013         size_t len = strlen( i ) + 1;
00014         memcpy( (void*)p, i, len );
00015         p += len;
00016 }
00017 
00019 void GenRPC::Push( char*& p, const char*const i, bool doEndianSwap ) {
00020         (void) doEndianSwap;
00021         size_t len = strlen( i ) + 1;           
00022         memcpy( (void*)p, i, len );
00023         p += len;
00024 }
00026 unsigned GenRPC::D_type( const char*const )    { return STR_PARAM; }
00028 unsigned GenRPC::D_type( char*const )          { return STR_PARAM; }
00029 
00031 unsigned GenRPC::D_type( float )              { return REAL_PARAM; }
00033 unsigned GenRPC::D_type( double )             { return REAL_PARAM; }
00035 unsigned GenRPC::D_type( long double )        { return REAL_PARAM; }
00036 
00038 size_t GenRPC::D_size( char*const str )       { return strlen( str ) + 1; }
00040 size_t GenRPC::D_size( char const *const str ){ return strlen( str ) + 1; }
00041 
00042 void GenRPC::SerializeHeader(char *&out, unsigned int numParams)
00043 {
00044         *out = (char) numParams;
00045         out++;
00046         //out[*writeOffset]=(char) numParams;
00047         //*writeOffset+=sizeof(unsigned char);
00048 }
00049 
00050 
00051 //
00052 // @params
00053 //            call: [IN/OUT] workspace to build parameters that we will pass to function
00054 //              in: [IN/OUT] is the serialized buffer - used as a temporary working for swapping
00055 //                  parameters.
00056 //        inLength: [IN] is the length of the above
00057 //       lastParam: [IN] final parameter, added onto the list
00058 //         thisPtr: [IN] if not zero - the value of this (added to start of list).
00059 //
00060 // @returns:
00061 //         true: parameter list created successfully.
00062 //        false: if deserialization fails for some reason.
00063 //
00064 bool GenRPC::DeserializeParametersAndBuildCall(
00065         CallParams &call,
00066         char *in, unsigned int inLength,
00067         void *lastParam, void *thisPtr
00068         ) {
00069 
00070 #if AUTO_RPC_ABI
00071 
00072                 NaturalWord *intCallParam = call.intParams;
00073 
00074                 char        *refParam = call.refParams;
00075 
00076 #if AUTO_RPC_ALLOC_SEPARATE_FLOATS
00077                 HardwareReal *realCallParam = call.realParams;
00078 #endif
00079 
00080 #if AUTO_RPC_CREATE_FLOAT_MAP
00081                 call.realMap = 0;
00082                 call.numRealParams = 0;
00083 #endif
00084 
00085 #if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
00086                 // large structure parameters have to be bumped up here - which corresponds with the start
00087                 // of the parameters that *are* passed on the stack.
00088                 NaturalWord *memParam = &call.intParams[ AUTO_RPC_INT_REG_PARAMS ];
00089 #endif
00090 
00091                 // this is first arg - assume space ;-)
00092 #pragma warning(disable:4311) // pointer truncation
00093                 if ( thisPtr )
00094                         *(intCallParam++) = reinterpret_cast<NaturalWord>( thisPtr );
00095 
00096                 unsigned int serializedArgs = *(unsigned char*)in;
00097 
00098                 unsigned char* header = (unsigned char*)in + 1;
00099 
00100                 unsigned char* data = &header[ serializedArgs * ( sizeof( unsigned int ) + 1 ) ];
00101 
00102                 // check we have the entire header in buffer
00103                 if ( data > (unsigned char*) &in[ inLength ] )
00104                         return 0;
00105 
00106                 for ( unsigned int i = 0; i < serializedArgs; i++ )
00107                 {
00108 
00109                         // read header entry
00110                         int plen = *(unsigned int*)header;
00111                         header += sizeof( unsigned int );
00112                         unsigned char const flags = *( header++ );
00113 
00114                         // Some bits are not used by the current implementation. So if we find them we bail because
00115                         // we clearly are not equipped to handle the data - and is there no safe way to "fail".
00116                         if ( flags & RESERVED_BITS )
00117                                 return 0;
00118 
00119 #ifndef __BITSTREAM_NATIVE_END
00120                         if (flags & DO_ENDIAN_SWAP)
00121                         {
00122                                 RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)&plen , sizeof( plen ) );
00123                         }
00124 #endif
00125 
00126                         if ( !plen || data + plen > (unsigned char*)&in[ inLength ] )
00127                                 return 0;
00128 
00129                         // handle null-terminated strings.
00130                         if (  ( flags & PARAM_TYPE_MASK ) == STR_PARAM )
00131                         {
00132 
00133                                 if ( intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
00134                                         return 0;
00135 
00136                                 // Check this has some sort of null termination. NB this assumes string is genuine Ascii
00137                                 // or UTF+8; using unicode (ie. UTF+16, UCS) could break this.
00138                                 if ( data[ plen - 1 ] != 0 )
00139                                         return 0;
00140 
00141                                 // The string doesn't need to be aligned, so we leave it in place; saving a copy, and
00142                                 // preventing clogging up of our buffers with data.
00143 
00144 #pragma warning(disable:4311) // pointer truncation
00145                                 *( intCallParam++ ) = reinterpret_cast<NaturalWord>( data );
00146 
00147                                 data += plen;
00148 
00149                                 continue;
00150                         }
00151 
00152 #ifndef __BITSTREAM_NATIVE_END
00153                         if (flags & DO_ENDIAN_SWAP)
00154                         {
00155                                 RakNet::BitStream::ReverseBytesInPlace( (unsigned char*)data , plen );
00156                         }
00157 #endif
00158 
00159                         // convert pointer to ref.
00160                         if (  ( flags & PARAM_TYPE_MASK ) == REF_PARAM
00161 #if AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
00162                                 || plen > AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD
00163 #endif
00164                                 )
00165                         {
00166                                 char *nextRefParam = refParam + AUTO_RPC__ALIGN_P2( plen, AUTO_RPC_REF_ALIGN );
00167 
00168                                 if ( nextRefParam >= AUTO_RPC_ARRAY_END( call.refParams ) || intCallParam + 1 >= AUTO_RPC_ARRAY_END( call.intParams ) )
00169                                         return 0;
00170 
00171                                 memcpy( refParam, data, plen );
00172 
00173 #pragma warning(disable:4311) // pointer truncation
00174                                 *( intCallParam++ ) = reinterpret_cast<NaturalWord>( refParam );
00175 
00176                                 refParam = nextRefParam;
00177 
00178                                 data += plen;
00179 
00180                                 continue;
00181                         }
00182 
00183                         // Guarantee we have space on the output stack to accommodate the parameter.
00184                         NaturalWord *nextParam = (NaturalWord*)( (char*)intCallParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
00185                         if ( nextParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
00186                                 return 0;
00187 
00188 #if AUTO_RPC_ALLOC_SEPARATE_FLOATS
00189                         if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM
00190                                 // long doubles, of various sizes (10, 16), all get passed on the stack
00191                                 && (size_t) plen <= sizeof(double)
00192                                 // once we've allocated all our floats, they get treated as ordinary int params
00193                                 && realCallParam < AUTO_RPC_ARRAY_END( call.realParams )
00194                                 )
00195                         {
00196 
00197                                 if ( plen != sizeof( float ) && plen != sizeof( double ) ) {
00198                                         printf("illegal float size %d\n", plen );
00199                                         // We can't handle it - it's not a real real :lol:
00200                                         return 0;
00201                                 }
00202 
00203 #ifdef __BIG_ENDIAN__
00204                                 memcpy( (char*)( realCallParam + 1 ) - plen, data, plen );
00205 #else
00206                                 memcpy( (char*)realCallParam, data, plen );
00207 #endif
00208 
00209 #if !AUTO_RPC_INT_SHADOW_OF_FLOATS
00210                                 // we didn't use the int slot, so don't allow an advance.
00211                                 nextParam = intCallParam;
00212 #endif
00213 
00214                                 // next time, we use the next Real slot
00215                                 realCallParam++;
00216                         }
00217 #if !AUTO_RPC_INT_SHADOW_OF_FLOATS
00218                         else
00219 #endif
00220 #endif  // AUTO_RPC_ALLOC_SEPARATE_FLOATS
00221                         {
00222                                 // the processor can atomically zero-extend small types, so even with the test,
00223                                 // it should be faster than memcpy+memset.
00224                                 if ( plen == 1 )
00225                                         *intCallParam = *(uint8_t*)data;    // should resolve to movzx and a move
00226                                 else if ( plen == 2 )
00227                                         *intCallParam = *(uint16_t*)data;  // if network order replace use htons(), and skip EndianSwap()
00228                                 else if ( plen == 4 )
00229                                         *intCallParam = *(uint32_t*)data;  // if network order replace use htonl(), and skip EndianSwap()
00230 #if AUTO_RPC_AUTORPC_WORD == 64
00231                                 else if ( plen == 8 )
00232                                         *intCallParam = *(uint64_t*)data;
00233 #endif
00234 
00235 #if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
00236                                 //
00237                                 // SYSV ABI: aggregates greater 16 bytes must go on the stack;
00238                                 // in practice, that means they can't come below AUTO_RPC_INT_REG_PARAMS when we call a function.
00239                                 //
00240                                 else if ( plen > 16 || ( plen > 8 && intCallParam == &call.intParams[ AUTO_RPC_INT_REG_PARAMS - 1] ) || ( flags & REAL_PARAM ) )
00241                                 {
00242                                         if ( intCallParam < memParam )
00243                                         {
00244                                                 NaturalWord*const nextMemParam = (NaturalWord*)( (char*)memParam + AUTO_RPC_ALIGN_P2( plen, NaturalWord ) );
00245 
00246                                                 if ( nextMemParam >= AUTO_RPC_ARRAY_END( call.intParams ) )
00247                                                         return 0;
00248 
00249                                                 memcpy( memParam, data, plen );
00250 
00251                                                 // prevent advancing the ptr slot, since we didn't use it.
00252                                                 nextParam = intCallParam;
00253 
00254                                                 // but advance the memparam
00255                                                 memParam = nextMemParam;
00256                                         }
00257                                         else
00258                                         {
00259                                                 memcpy( (void*)intCallParam, data, plen );
00260                                         }
00261                                 }
00262 #endif // AUTO_RPC_ABI_SYSV_AMD64
00263                                 else
00264                                 {
00265                                         // We don't need to worry about alignment, because any type that's not a whole multiple
00266                                         // of the natual word size will be an aggregate and that should be at the base of memory -
00267                                         // this is true for some PowerPC systems  (see [e]) but not all.  But hey, you
00268                                         // probably should be passing such structs by reference.
00269                                         //
00270                                         // Zeroing is also unecessary as code shouldn't be reading beyodn the bounds of the structure.
00271                                         //
00272                                         memcpy( (void*)intCallParam, data, plen );
00273                                 }
00274 
00275                         }
00276 
00277 #if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
00278                         // skip over any stored "class MEMORY" (see [b]) parameters.
00279                         if ( nextParam == &call.intParams[AUTO_RPC_INT_REG_PARAMS] )
00280                                 intCallParam = memParam;
00281                         else
00282 #endif
00283                                 // advance to next output param
00284                                 intCallParam = nextParam;
00285 
00286 #if !AUTO_RPC_ALLOC_SEPARATE_FLOATS && AUTO_RPC_CREATE_FLOAT_MAP
00287                         if ( ( flags & PARAM_TYPE_MASK ) == REAL_PARAM && i < AUTO_RPC_FLOAT_REG_PARAMS && ( plen == sizeof( double ) || plen == sizeof( float ) ) )                    
00288                         {
00289                                 call.numRealParams++;
00290                                 call.realMap |= ( 1 << i );
00291                         }
00292 #endif
00293 
00294                         // advance to next input arg.
00295                         data += plen;
00296                 }
00297 
00298                 // space for lastParam?
00299                 if ( &intCallParam[1] >= AUTO_RPC_ARRAY_END( call.intParams ) )
00300                         return 0;
00301 
00302 #pragma warning(disable:4311) // pointer truncation
00303                 *( intCallParam++ ) = reinterpret_cast<NaturalWord >( lastParam );
00304 
00305 #if AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
00306                 // figure out how many args we have notched up.
00307                 if ( memParam > &call.intParams[AUTO_RPC_INT_REG_PARAMS] && memParam > intCallParam )
00308                         intCallParam = memParam;
00309 #endif
00310 
00311                 // convert from ptrdif_t to unsigned int; should be small enough, even if its 64-bit pointers.
00312                 call.numIntParams = ( unsigned int )( intCallParam - call.intParams );
00313 
00314 #if AUTO_RPC_FLOAT_REG_PARAMS && AUTO_RPC_ALLOC_SEPARATE_FLOATS
00315                 call.numRealParams = ( unsigned int )( realCallParam - call.realParams );
00316 #endif
00317 
00318                 return 1;
00319 #else // AUTO_RPC_ABI
00320                 return 0;
00321 #endif
00322 
00323 }
00324 
00325 
00326 //
00327 // @params
00328 //   callParams: [IN] parameter list
00329 //  functionPtr: [IN] function to call.
00330 //
00331 // @returns:
00332 //         true: function was called.
00333 //        false: too many parameters, probably.
00334 //
00335 bool GenRPC::CallWithStack( CallParams& call, void *functionPtr ) {
00336 #if AUTO_RPC_ABI
00337         // Are we x86-32?
00338 #if !defined( AUTO_RPC_NO_ASM ) && ( defined(__i386__) || defined( _M_IX86 ) || defined( __INTEL__ ) )
00339 #if !defined(__GNUC__)
00340         // Intel dialect assembly
00341         NaturalWord const paramc = call.numIntParams;
00342 #pragma warning(disable:4311) // pointer truncation
00343         NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
00344         _asm
00345         {
00346 
00347                         // Load numbytes.
00348                         mov         ecx, paramc
00349 
00350                         // allocate space on the stack for all these params
00351                         lea         edi,dword ptr[ecx * 4]
00352                         sub         esp,edi
00353 
00354                         // setup source of copy
00355                         mov         esi, paramv
00356 
00357                         // Setup the destination of the copy: the return stack.
00358                         mov         edi,esp
00359 
00360                         // copy data
00361                         rep movs    dword ptr es:[edi],dword ptr [esi]
00362 
00363                         // call the function
00364                         call        functionPtr
00365 
00366                         // Restore the stack to its state, prior to our invocation.
00367                         //
00368                         // Detail: edi is one of the registers that must be preserved
00369                         // across function calls. (The compiler should be saving it for us.)
00370                         //
00371                         // We left edi pointing to the end of the block copied; i.e. the state
00372                         // of the stack prior to copying our params.  So by loading it
00373                         // into the esp we can restore the return stack to the state prior
00374                         // to the copy.
00375                         //
00376                         mov         esp,edi
00377         };
00378 #else
00379         // GCC has its own form of asm block - so we'll always have to write two versions.
00380         // Therefore, as we're writing it twice, we use the ATT dialect, because only later
00381         // gcc support Intel dialect.  This one also aligns the stack to a multiple of 16 bytes; which
00382         // windows doesn't seem to care about.
00383         // Be aware, we can't use offset of to get the address, as gcc insists on sticking.
00384         // NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
00385         asm (\
00386                 "lea    4(%%ecx),%%esi\n\
00387                 mov    (%%ecx),%%ecx\n\
00388                 lea    (,%%ecx,4),%%edi\n\
00389                 sub    %%edi,%%esp\n\
00390                 mov    $12,%%edx\n\
00391                 and    %%esp,%%edx\n\
00392                 sub    %%edx,%%esp\n\
00393                 mov    %%esp,%%edi\n\
00394                 rep movsl %%ds:(%%esi),%%es:(%%edi)\n\
00395                 add    %%edx,%%edi\n\
00396                 call   *%1\n\
00397                 mov    %%edi,%%esp"\
00398                 : /* no outputs */\
00399                 : "c" ( &call ), "m" (functionPtr)\
00400                 : "%edi" , "%esi", "%edx", "%eax"\
00401                 );
00402 #endif  // GNUC vs non GNUC
00403         return 1;
00404 #elif !defined( AUTO_RPC_NO_ASM ) && ( defined( _M_X64 ) || defined( __x86_64__ ) || defined( _M_AMD64 ) )
00405 #if AUTO_RPC_ABI == AUTO_RPC_ABI_WIN_AMD64
00406         NaturalWord const paramv = reinterpret_cast<NaturalWord>( call.intParams );
00407         _asm {
00408                 // rcx := number of qwords to copy
00409                 mov         rcx, paramc
00410 
00411                         // r9 := 0
00412                         sub         r9,r9
00413 
00414                         // rsi => our parameter list.
00415                         mov         rsi, paramv
00416 
00417                         // r9 := -(number of qwords to copy)
00418                         sub         r9,rcx
00419 
00420                         // Preparation to align the stack to 16 byte boundary
00421                         mov         rdx,8
00422 
00423                         // rdi => projected bottom of stack
00424                         lea         rdi,dword ptr[rsp + r9 * 8]
00425 
00426                 // figure out if stack needs aligning
00427                 and         rdx,rdi
00428 
00429                         // save stack into rbx
00430                         mov         rbx,rsp
00431 
00432                         // align stack
00433                         sub         rdi,rdx
00434                         mov         rsp,rdi
00435 
00436                         // rdx => our parameter list
00437                         mov         rdx,rsi
00438 
00439                         //
00440                         // copy data - we copy all parameters, because we have to
00441                         // create a shadow area; and this way its easiest.
00442                         //
00443                         rep movs     qword ptr es:[edi],qword ptr [esi]
00444 
00445                 // load registers
00446                 // rcx|xmm0, rdx|xmm1,r8|xmm2,r9|xmm3
00447                 mov          rcx,qword ptr [rdx]
00448                 mov          r8,qword ptr 16[rdx]
00449                 movq         xmm0,rcx
00450                         mov          r9,qword ptr 24[rdx]
00451                 movq         xmm2,r8
00452                         mov          rdx,qword ptr 8[rdx]
00453                 movq         xmm3,r9
00454                         movq         xmm1,rdx
00455 
00456                         // call the function
00457                         call        functionPtr
00458 
00459                         // Restore the stack to its state, prior to our invocation -
00460                         // saved in rbx.
00461                         mov         rsp,rbx
00462         }
00463 #elif AUTO_RPC_ABI == AUTO_RPC_ABI_SYSV_AMD64
00464         //
00465         // GCC won't generate a stack frame on higher optimization levels, so we don't touch it.
00466         // on -O3 it inlines the code, breaking it because of the jump reference.
00467         //
00468         // I figure a 64-bit compiler will be recent enough to do Intel syntax. May need to change
00469         // my mind on that. NB. Structure members are hard coded into this.
00470         //
00471         asm (\
00472                 ".intel_syntax noprefix\n\
00473                 push        rbx\n\
00474                 mov         rax,rsi\n\
00475                 push        r15\n\
00476                 mov         ecx,dword ptr[rdi+8+8*8]\n\
00477                 lea         rsi,[rdi+8+8*8+8]\n\
00478                 mov         r15,rsp\n\
00479                 lea         rbx,[rdi+8]\n\
00480                 sub         r8,r8\n\
00481                 sub         rcx,6\n\
00482                 lea         r9,[rsi + 6 * 8]\n\
00483                 jbe         .L1\n\
00484                 sub         r8,rcx\n\
00485                 mov         rdx,8\n\
00486                 lea         rdi,qword ptr[rsp + r8 * 8]\n\
00487                 and         rdx,rdi\n\
00488                 mov         rsi,r9\n\
00489                 sub         rdi,rdx\n\
00490                 mov         rsp,rdi\n\
00491                 rep movsq   \n\
00492                 .L1:\n\
00493                 movq         xmm0,[rbx]\n\
00494                 movq         xmm1,[rbx+8]\n\
00495                 movq         xmm2,[rbx+16]\n\
00496                 movq         xmm3,[rbx+24]\n\
00497                 movq         xmm4,[rbx+32]\n\
00498                 movq         xmm5,[rbx+40]\n\
00499                 movq         xmm6,[rbx+48]\n\
00500                 movq         xmm7,[rbx+56]\n\
00501                 mov          rdi,[r9-48]\n\
00502                 mov          rsi,[r9-40]\n\
00503                 mov          rdx,[r9-32]\n\
00504                 mov          rcx,[r9-24]\n\
00505                 mov          r8,[r9-16]\n\
00506                 mov          r9,[r9-8]\n\
00507                 call         rax\n\
00508                 mov          rsp,r15\n\
00509                 pop          r15\n\
00510                 pop          rbx\n\
00511                 .att_syntax prefix"\
00512                 : /* no outputs */\
00513                 : "D" ( &call ), "S" (functionPtr)\
00514                 : "%rdx", "%rcx" , "%r8", "%r9", "%rax",\
00515                 "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" );
00516         // : "D", ( &call ), "c" ( &call.numIntParams ), "S" ( paramv ), "b" ( floatv ), "a" (functionPtr)
00517 #else
00518 #error unsupport ABI
00519 #endif
00520         return 1;
00521 #else
00522         // AUTO_RPC_NO_ASM or no x86-32/x86-64
00523         //
00524         //  4.  Passing the parameters.
00525         //
00526         //  The compiler knows how to call functions, so having sorted out the argument list,
00527         //  we just pass it to a function of the correct form - and let the compiler align stacks,
00528         //  load registers, place parameters where they should be.
00529         //
00530         //  This is particularly important as GCC has control over the stack frame, and it can
00531         //  improperly frame it - for instance utilising red zones to save args, rather than pushing them.
00532         //  On PowerPC it must create the parameter passing area, too.
00533         //
00534         //  The most brute force way, is to code a function call for every possible number of parameters
00535         //
00536         //  switch( paramc ) {
00537         //        case 1:   ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord)) myfunc)( callParam[0] ); break;
00538         //        case 2:   ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1] ); break;
00539         //        ...
00540         //        case 64:  ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord)) myfunc)( callParam[0], callParam[1], ... , callParam[63] ); break;
00541         //  }
00542         //
00543         //  This is the only way to code WIN32 stdcall, for example, as the args must match exactly;
00544         //  and so the only way to call from C if you need to call WINAPI routines.
00545         //
00546         //  2) Fortunately most calling conventions allowing excessive args. So this means we could
00547         //  write something like below:
00548         //
00549         //     ( (void(*)(...)) myfunc )( args[0],...,args[63] );
00550         //
00551         //  And although this should work, its a huge performance penalty copying between memory
00552         //  locations for so many args.
00553         //
00554         //  So we compromise - and do a stepped sequence. Noticing that the WIN64 ABI alwys requires
00555         //  space for three args anyway.
00556         //
00557         //  And on SysV x64 systems, the first 6 args are passed in reg; so again, these are only
00558         //  copies into register, not memory copies.  And finally that if we load word[n], word[n+1]
00559         //  is loaded into the cache - thus the overhead for loading is not as big as it might be.
00560         //
00561         //  For most realistic cases, a dozen args would be excessive.  Obviously, if you have
00562         //  a tested assembler equivalent, its probably better to use that.
00563         //
00564         //
00565 #if AUTO_RPC_FLOAT_REG_PARAMS
00566         if ( call.numRealParams == 0 )
00567 #endif
00568         {
00569                 if ( call.numIntParams <= 3 )
00570                 {
00571                         ( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_3)) functionPtr )( AUTO_RPC_INT_ARGS_3(  call ) );
00572                         return 1;
00573                 }
00574                 if ( call.numIntParams <= 6 )
00575                 {
00576                         ( (void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_6)) functionPtr )( AUTO_RPC_INT_ARGS_6( call ) );
00577                         return 1;
00578                 }
00579                 if ( call.numIntParams <= 9 )
00580                 {
00581                         ((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_9))functionPtr)( AUTO_RPC_INT_ARGS_9( call ) );
00582                         return 1;
00583                 }
00584                 if ( call.numIntParams <= 12 )
00585                 {
00586                         ((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_12))functionPtr)( AUTO_RPC_INT_ARGS_12( call ) );
00587                         return 1;
00588                 }
00589                 if ( call.numIntParams <= 32 )
00590                 {
00591                         ((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_32))functionPtr)( AUTO_RPC_INT_ARGS_32( call ) );
00592                         return 1;
00593                 }
00594                 if ( call.numIntParams <= 64 )
00595                 {
00596                         ((void(AUTO_RPC_CALLSPEC*)(AUTO_RPC_NW_64))functionPtr)( AUTO_RPC_INT_ARGS_64( call ) );
00597                         return 1;
00598                 }
00599         }
00600 #if AUTO_RPC_FLOAT_REG_PARAMS && !AUTO_RPC_ALLOC_SEPARATE_FLOATS
00601         else
00602         {
00603                 if ( call.numIntParams > 64 ) return 0;
00604 
00605                 switch( call.realMap )
00606                 {
00607                         // case 0: - no floats, never happens here.
00608 
00609                 case 1: ( (void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00610                                         call.realParams[0], call.intParams[1], call.intParams[2], call.intParams[3],
00611                                         AUTO_RPC_INT_ARGS_4_64( call )
00612                                         );
00613                         break;
00614 
00615                 case 2:
00616                         ((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00617                                 call.intParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
00618                                 AUTO_RPC_INT_ARGS_4_64( call )
00619                                 );
00620                         break;
00621 
00622                 case 3:
00623                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00624                                 call.realParams[0], call.realParams[1], call.intParams[2], call.intParams[3],
00625                                 AUTO_RPC_INT_ARGS_4_64( call )
00626                                 );
00627                         break;
00628 
00629                 case 4: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00630                                         call.intParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
00631                                         AUTO_RPC_INT_ARGS_4_64( call )
00632                                         );
00633                         break;
00634 
00635                 case 5:
00636                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00637                                 call.realParams[0], call.intParams[1], call.realParams[2], call.intParams[3],
00638                                 AUTO_RPC_INT_ARGS_4_64( call )
00639                                 );
00640                         break;
00641 
00642                 case 6:
00643                         ((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00644                                 call.intParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
00645                                 AUTO_RPC_INT_ARGS_4_64( call )
00646                                 );
00647                         break;
00648 
00649                 case 7:
00650                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,NaturalWord,AUTO_RPC_NW_4_64))functionPtr)(
00651                                 call.realParams[0], call.realParams[1], call.realParams[2], call.intParams[3],
00652                                 AUTO_RPC_INT_ARGS_4_64( call )
00653                                 );
00654                         break;
00655 
00656                 case 8: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00657                                         call.intParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
00658                                         AUTO_RPC_INT_ARGS_4_64( call )
00659                                         );
00660                         break;
00661 
00662                 case 9:
00663                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00664                                 call.realParams[0], call.intParams[1], call.intParams[2], call.realParams[3],
00665                                 AUTO_RPC_INT_ARGS_4_64( call )
00666                                 );
00667                         break;
00668                 case 10:
00669                         ((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00670                                 call.intParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
00671                                 AUTO_RPC_INT_ARGS_4_64( call )
00672                                 );
00673                         break;
00674 
00675 
00676                 case 11:
00677                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,NaturalWord,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00678                                 call.realParams[0], call.realParams[1], call.intParams[2], call.realParams[3],
00679                                 AUTO_RPC_INT_ARGS_4_64( call )
00680                                 );
00681                         break;
00682 
00683                 case 12: ( (void(AUTO_RPC_CALLSPEC*)(NaturalWord,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00684                                          call.intParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
00685                                          AUTO_RPC_INT_ARGS_4_64( call )
00686                                          );
00687                         break;
00688 
00689                 case 13:
00690                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,NaturalWord,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00691                                 call.realParams[0], call.intParams[1], call.realParams[2], call.realParams[3],
00692                                 AUTO_RPC_INT_ARGS_4_64( call )
00693                                 );
00694                         break;
00695 
00696                 case 14:
00697                         ((void(AUTO_RPC_CALLSPEC*)(NaturalWord,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00698                                 call.intParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
00699                                 AUTO_RPC_INT_ARGS_4_64( call )
00700                                 );
00701                         break;
00702 
00703                 case 15:
00704                         ((void(AUTO_RPC_CALLSPEC*)(HardwareReal,HardwareReal,HardwareReal,HardwareReal,AUTO_RPC_NW_4_64))functionPtr)(
00705                                 call.realParams[0], call.realParams[1], call.realParams[2], call.realParams[3],
00706                                 AUTO_RPC_INT_ARGS_4_64( call )
00707                                 );
00708                         break;
00709 
00710                 default: return 0;
00711                 }
00712         }
00713 #elif AUTO_RPC_FLOAT_REG_PARAMS
00714         else
00715         {
00716                 // we pass FLOAT args last for powerpc compatibility. And although it means we pass them twice,
00717                 // they should end up in the correct floating point register, with the rest of the integers in the
00718                 // correct place...
00719                 //
00720                 // NB if you want to write inline asm for powerpc, you'll have to be put it in a separate
00721                 // "naked" function to that uou can setup the parameter passing area and ensure its big enough.
00722                 // (GCC will delete functions that are unused - it will delete the body of functions that
00723                 // aren't called.)
00724                 //
00725                 if ( call.numIntParams <= 3 )
00726                 {
00727                         ((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 ) );
00728                         return 1;
00729                 }
00730                 if ( call.numIntParams <= 6 )
00731                 {
00732                         ((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 ) );
00733                         return 1;
00734                 }
00735                 if ( call.numIntParams <= 9 )
00736                 {
00737                         ((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 ) );
00738                         return 1;
00739                 }
00740                 if ( call.numIntParams <= 12 )
00741                 {
00742                         ( (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 ) );
00743                         return 1;
00744                 }
00745                 if ( call.numIntParams <= 64 )
00746                 {
00747                         ( (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 ) );
00748                         return 1;
00749                 }
00750         }
00751 #endif   // AUTO_RPC_FLOAT_REG_PARAMS
00752         return 0;
00753 #endif   // AUTO_RPC_NO_ASM
00754 #else  // AUTO_RPC_ABI
00755         return 0;
00756 #endif
00757 }
00758 // --8<---8<----8<----8<---END

Generated on Thu Sep 30 2010 01:27:24 for RakNet by  doxygen 1.7.1