2014-10-27 18:43:09 -04:00
/*
AngelCode Scripting Library
2015-05-11 19:40:43 -04:00
Copyright ( c ) 2003 - 2014 Andreas Jonsson
2014-10-27 18:43:09 -04:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any
damages arising from the use of this software .
Permission is granted to anyone to use this software for any
purpose , including commercial applications , and to alter it and
redistribute it freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you
must not claim that you wrote the original software . If you use
this software in a product , an acknowledgment in the product
documentation would be appreciated but is not required .
2. Altered source versions must be plainly marked as such , and
must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source
distribution .
The original version of this library can be located at :
http : //www.angelcode.com/angelscript/
Andreas Jonsson
andreas @ angelcode . com
*/
//
// as_callfunc_ppc.cpp
//
// These functions handle the actual calling of system functions
//
// This version is PPC specific
//
# include <stdio.h>
# include "as_config.h"
# ifndef AS_MAX_PORTABILITY
# ifdef AS_PPC
# include "as_callfunc.h"
# include "as_scriptengine.h"
# include "as_texts.h"
# include "as_tokendef.h"
# include "as_context.h"
# include <stdlib.h>
BEGIN_AS_NAMESPACE
// This part was originally written by Pecan Heber, June 2006, for
// use on MacOS X with 32bit PPC processor. He based the code on the
// code in as_callfunc_sh4.cpp
# define AS_PPC_MAX_ARGS 32
// The array used to send values to the correct places.
// Contains a byte of argTypes to indicate the register tYpe to load
// or zero if end of arguments
// The +1 is for when CallThis (object methods) is used
// Extra +1 when returning in memory
// Extra +1 in ppcArgsType to ensure zero end-of-args marker
// TODO: multithread: We need to remove these global variables for thread-safety
enum argTypes { ppcENDARG , ppcINTARG , ppcFLOATARG , ppcDOUBLEARG } ;
static asDWORD ppcArgs [ 2 * AS_PPC_MAX_ARGS + 1 + 1 ] ;
// Using extern "C" because we use this symbol name in the assembly code
extern " C "
{
static asBYTE ppcArgsType [ 2 * AS_PPC_MAX_ARGS + 1 + 1 + 1 ] ;
}
// NOTE: these values are for PowerPC 32 bit.
# define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame
# define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc()
# define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore
# define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame
# define PPC_STACK_SIZE(numParams) (-( ( ((((numParams)<8)?8:(numParams))<<2) + EXTRA_STACK_SIZE + 15 ) & ~15 )) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes
// Loads all data into the correct places and calls the function.
// ppcArgsType is an array containing a byte type (enum argTypes) for each argument.
// stackArgSize is the size in bytes for how much data to put on the stack frame
extern " C " asQWORD ppcFunc ( const asDWORD * argsPtr , int StackArgSize , asDWORD func ) ;
asm ( " .text \n "
" .align 2 \n " // align the code to 1 << 2 = 4 bytes
" .globl _ppcFunc \n "
" _ppcFunc: \n "
// We're receiving the following parameters
// r3 : argsPtr
// r4 : StackArgSize
// r5 : func
// The following registers are used through out the function
// r31 : the address of the label address, as reference for all other labels
// r30 : temporary variable
// r29 : arg list pointer
// r28 : number of FPR registers used by the parameters
// r27 : the function pointer that will be called
// r26 : the location of the parameters for the call
// r25 : arg type list pointer
// r24 : temporary variable
// r23 : number of GPR registers used by the parameters
// r1 : this is stack pointer
// r0 : temporary variable
// f0 : temporary variable
// We need to store some of the registers for restoral before returning to caller
// lr - always stored in 8(r1) - this is the return address
// cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register
// r1 - always stored in 0(r1) - this is the stack pointer
// r11
// r13 to r31
// f14 to f31
// Store register values and setup our stack frame
" mflr r0 \n " // move the return address into r0
" stw r0, 8(r1) \n " // Store the return address on the stack
" stmw r23, -36(r1) \n " // Store registers r23 to r31 on the stack
" stwux r1, r1, r4 \n " // Increase the stack with the needed space and store the original value in the destination
// Obtain an address that we'll use as our position of reference when obtaining addresses of other labels
" bl address \n "
" address: \n "
" mflr r31 \n "
// initial registers for the function
" mr r29, r3 \n " // (r29) args list
" mr r27, r5 \n " // load the function pointer to call. func actually holds the pointer to our function
" addi r26, r1, 24 \n " // setup the pointer to the parameter area to the function we're going to call
" sub r0, r0, r0 \n " // zero out r0
" mr r23, r0 \n " // zero out r23, which holds the number of used GPR registers
" mr r28, r0 \n " // zero our r22, which holds the number of used float registers
// load the global ppcArgsType which holds the types of arguments for each argument
" addis r25, r31, ha16(_ppcArgsType - address) \n " // load the upper 16 bits of the address to r25
" la r25, lo16(_ppcArgsType - address)(r25) \n " // load the lower 16 bits of the address to r25
" subi r25, r25, 1 \n " // since we increment r25 on its use, we'll pre-decrement it
// loop through the arguments
" ppcNextArg: \n "
" addi r25, r25, 1 \n " // increment r25, our arg type pointer
// switch based on the current argument type (0:end, 1:int, 2:float 3:double)
" lbz r24, 0(r25) \n " // load the current argument type (it's a byte)
" mulli r24, r24, 4 \n " // our jump table has 4 bytes per case (1 instruction)
" addis r30, r31, ha16(ppcTypeSwitch - address) \n " // load the address of the jump table for the switch
" la r30, lo16(ppcTypeSwitch - address)(r30) \n "
" add r0, r30, r24 \n " // offset by our argument type
" mtctr r0 \n " // load the jump address into CTR
" bctr \n " // jump into the jump table/switch
" nop \n "
// the jump table/switch based on the current argument type
" ppcTypeSwitch: \n "
" b ppcArgsEnd \n "
" b ppcArgIsInteger \n "
" b ppcArgIsFloat \n "
" b ppcArgIsDouble \n "
// when we get here we have finished processing all the arguments
// everything is ready to go to call the function
" ppcArgsEnd: \n "
" mtctr r27 \n " // the function pointer is stored in r27, load that into CTR
" bctrl \n " // call the function. We have to do it this way so that the LR gets the proper
" nop \n " // return value (the next instruction below). So we have to branch from CTR instead of LR.
// Restore registers and caller's stack frame, then return to caller
" lwz r1, 0(r1) \n " // restore the caller's stack pointer
" lwz r0, 8(r1) \n " // load in the caller's LR
" mtlr r0 \n " // restore the caller's LR
" lmw r23, -36(r1) \n " // restore registers r23 to r31 from the stack
" blr \n " // return back to the caller
" nop \n "
// Integer argument (GPR register)
" ppcArgIsInteger: \n "
" addis r30, r31, ha16(ppcLoadIntReg - address) \n " // load the address to the jump table for integer registers
" la r30, lo16(ppcLoadIntReg - address)(r30) \n "
" mulli r0, r23, 8 \n " // each item in the jump table is 2 instructions (8 bytes)
" add r0, r0, r30 \n " // calculate ppcLoadIntReg[numUsedGPRRegs]
" lwz r30, 0(r29) \n " // load the next argument from the argument list into r30
" cmpwi r23, 8 \n " // we can only load GPR3 through GPR10 (8 registers)
" bgt ppcLoadIntRegUpd \n " // if we're beyond 8 GPR registers, we're in the stack, go there
" mtctr r0 \n " // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers)
" bctr \n " // load the argument into a GPR register
" nop \n "
// jump table for GPR registers, for the first 8 GPR arguments
" ppcLoadIntReg: \n "
" mr r3, r30 \n " // arg0 (to r3)
" b ppcLoadIntRegUpd \n "
" mr r4, r30 \n " // arg1 (to r4)
" b ppcLoadIntRegUpd \n "
" mr r5, r30 \n " // arg2 (to r5)
" b ppcLoadIntRegUpd \n "
" mr r6, r30 \n " // arg3 (to r6)
" b ppcLoadIntRegUpd \n "
" mr r7, r30 \n " // arg4 (to r7)
" b ppcLoadIntRegUpd \n "
" mr r8, r30 \n " // arg5 (to r8)
" b ppcLoadIntRegUpd \n "
" mr r9, r30 \n " // arg6 (to r9)
" b ppcLoadIntRegUpd \n "
" mr r10, r30 \n " // arg7 (to r10)
" b ppcLoadIntRegUpd \n "
// all GPR arguments still go on the stack
" ppcLoadIntRegUpd: \n "
" stw r30, 0(r26) \n " // store the argument into the next slot on the stack's argument list
" addi r23, r23, 1 \n " // count a used GPR register
" addi r29, r29, 4 \n " // move to the next argument on the list
" addi r26, r26, 4 \n " // adjust our argument stack pointer for the next
" b ppcNextArg \n " // next argument
// single Float argument
" ppcArgIsFloat: \n "
" addis r30, r31, ha16(ppcLoadFloatReg - address) \n " // get the base address of the float register jump table
" la r30, lo16(ppcLoadFloatReg - address)(r30) \n "
" mulli r0, r28, 8 \n " // each jump table entry is 8 bytes
" add r0, r0, r30 \n " // calculate the offset to ppcLoadFloatReg[numUsedFloatReg]
" lfs f0, 0(r29) \n " // load the next argument as a float into f0
" cmpwi r28, 13 \n " // can't load more than 13 float/double registers
" bgt ppcLoadFloatRegUpd \n " // if we're beyond 13 registers, just fall to inserting into the stack
" mtctr r0 \n " // jump into the float jump table
" bctr \n "
" nop \n "
// jump table for float registers, for the first 13 float arguments
" ppcLoadFloatReg: \n "
" fmr f1, f0 \n " // arg0 (f1)
" b ppcLoadFloatRegUpd \n "
" fmr f2, f0 \n " // arg1 (f2)
" b ppcLoadFloatRegUpd \n "
" fmr f3, f0 \n " // arg2 (f3)
" b ppcLoadFloatRegUpd \n "
" fmr f4, f0 \n " // arg3 (f4)
" b ppcLoadFloatRegUpd \n "
" fmr f5, f0 \n " // arg4 (f5)
" b ppcLoadFloatRegUpd \n "
" fmr f6, f0 \n " // arg5 (f6)
" b ppcLoadFloatRegUpd \n "
" fmr f7, f0 \n " // arg6 (f7)
" b ppcLoadFloatRegUpd \n "
" fmr f8, f0 \n " // arg7 (f8)
" b ppcLoadFloatRegUpd \n "
" fmr f9, f0 \n " // arg8 (f9)
" b ppcLoadFloatRegUpd \n "
" fmr f10, f0 \n " // arg9 (f10)
" b ppcLoadFloatRegUpd \n "
" fmr f11, f0 \n " // arg10 (f11)
" b ppcLoadFloatRegUpd \n "
" fmr f12, f0 \n " // arg11 (f12)
" b ppcLoadFloatRegUpd \n "
" fmr f13, f0 \n " // arg12 (f13)
" b ppcLoadFloatRegUpd \n "
" nop \n "
// all float arguments still go on the stack
" ppcLoadFloatRegUpd: \n "
" stfs f0, 0(r26) \n " // store, as a single float, f0 (current argument) on to the stack argument list
" addi r23, r23, 1 \n " // a float register eats up a GPR register
" addi r28, r28, 1 \n " // ...and, of course, a float register
" addi r29, r29, 4 \n " // move to the next argument in the list
" addi r26, r26, 4 \n " // move to the next stack slot
" b ppcNextArg \n " // on to the next argument
" nop \n "
// double Float argument
" ppcArgIsDouble: \n "
" addis r30, r31, ha16(ppcLoadDoubleReg - address) \n " // load the base address of the jump table for double registers
" la r30, lo16(ppcLoadDoubleReg - address)(r30) \n "
" mulli r0, r28, 8 \n " // each slot of the jump table is 8 bytes
" add r0, r0, r30 \n " // calculate ppcLoadDoubleReg[numUsedFloatReg]
" lfd f0, 0(r29) \n " // load the next argument, as a double float, into f0
" cmpwi r28, 13 \n " // the first 13 floats must go into float registers also
" bgt ppcLoadDoubleRegUpd \n " // if we're beyond 13, then just put on to the stack
" mtctr r0 \n " // we're under 13, first load our register
" bctr \n " // jump into the jump table
" nop \n "
// jump table for float registers, for the first 13 float arguments
" ppcLoadDoubleReg: \n "
" fmr f1, f0 \n " // arg0 (f1)
" b ppcLoadDoubleRegUpd \n "
" fmr f2, f0 \n " // arg1 (f2)
" b ppcLoadDoubleRegUpd \n "
" fmr f3, f0 \n " // arg2 (f3)
" b ppcLoadDoubleRegUpd \n "
" fmr f4, f0 \n " // arg3 (f4)
" b ppcLoadDoubleRegUpd \n "
" fmr f5, f0 \n " // arg4 (f5)
" b ppcLoadDoubleRegUpd \n "
" fmr f6, f0 \n " // arg5 (f6)
" b ppcLoadDoubleRegUpd \n "
" fmr f7, f0 \n " // arg6 (f7)
" b ppcLoadDoubleRegUpd \n "
" fmr f8, f0 \n " // arg7 (f8)
" b ppcLoadDoubleRegUpd \n "
" fmr f9, f0 \n " // arg8 (f9)
" b ppcLoadDoubleRegUpd \n "
" fmr f10, f0 \n " // arg9 (f10)
" b ppcLoadDoubleRegUpd \n "
" fmr f11, f0 \n " // arg10 (f11)
" b ppcLoadDoubleRegUpd \n "
" fmr f12, f0 \n " // arg11 (f12)
" b ppcLoadDoubleRegUpd \n "
" fmr f13, f0 \n " // arg12 (f13)
" b ppcLoadDoubleRegUpd \n "
" nop \n "
// all float arguments still go on the stack
" ppcLoadDoubleRegUpd: \n "
" stfd f0, 0(r26) \n " // store f0, as a double, into the argument list on the stack
" addi r23, r23, 2 \n " // a double float eats up two GPRs
" addi r28, r28, 1 \n " // ...and, of course, a float
" addi r29, r29, 8 \n " // increment to our next argument we need to process (8 bytes for the 64bit float)
" addi r26, r26, 8 \n " // increment to the next slot on the argument list on the stack (8 bytes)
" b ppcNextArg \n " // on to the next argument
" nop \n "
) ;
asDWORD GetReturnedFloat ( )
{
asDWORD f ;
asm ( " stfs f1, %0 \n " : " =m " ( f ) ) ;
return f ;
}
asQWORD GetReturnedDouble ( )
{
asQWORD f ;
asm ( " stfd f1, %0 \n " : " =m " ( f ) ) ;
return f ;
}
// puts the arguments in the correct place in the stack array. See comments above.
void stackArgs ( const asDWORD * args , const asBYTE * argsType , int & numIntArgs , int & numFloatArgs , int & numDoubleArgs )
{
int i ;
int argWordPos = numIntArgs + numFloatArgs + ( numDoubleArgs * 2 ) ;
int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs ;
int typeIndex ;
for ( i = 0 , typeIndex = 0 ; ; i + + , typeIndex + + )
{
// store the type
ppcArgsType [ typeOffset + + ] = argsType [ typeIndex ] ;
if ( argsType [ typeIndex ] = = ppcENDARG )
break ;
switch ( argsType [ typeIndex ] )
{
case ppcFLOATARG :
// stow float
ppcArgs [ argWordPos ] = args [ i ] ; // it's just a bit copy
numFloatArgs + + ;
argWordPos + + ; //add one word
break ;
case ppcDOUBLEARG :
// stow double
memcpy ( & ppcArgs [ argWordPos ] , & args [ i ] , sizeof ( double ) ) ; // we have to do this because of alignment
numDoubleArgs + + ;
argWordPos + = 2 ; //add two words
i + + ; //doubles take up 2 argument slots
break ;
case ppcINTARG :
// stow register
ppcArgs [ argWordPos ] = args [ i ] ;
numIntArgs + + ;
argWordPos + + ;
break ;
}
}
// close off the argument list (if we have max args we won't close it off until here)
ppcArgsType [ typeOffset ] = ppcENDARG ;
}
static asQWORD CallCDeclFunction ( const asDWORD * pArgs , const asBYTE * pArgsType , int argSize , asDWORD func , void * retInMemory )
{
int baseArgCount = 0 ;
if ( retInMemory )
{
// the first argument is the 'return in memory' pointer
ppcArgs [ 0 ] = ( asDWORD ) retInMemory ;
ppcArgsType [ 0 ] = ppcINTARG ;
ppcArgsType [ 1 ] = ppcENDARG ;
baseArgCount = 1 ;
}
// put the arguments in the correct places in the ppcArgs array
int numTotalArgs = baseArgCount ;
if ( argSize > 0 )
{
int intArgs = baseArgCount , floatArgs = 0 , doubleArgs = 0 ;
stackArgs ( pArgs , pArgsType , intArgs , floatArgs , doubleArgs ) ;
numTotalArgs = intArgs + floatArgs + 2 * doubleArgs ; // doubles occupy two slots
}
else
{
// no arguments, cap the type list
ppcArgsType [ baseArgCount ] = ppcENDARG ;
}
// call the function with the arguments
return ppcFunc ( ppcArgs , PPC_STACK_SIZE ( numTotalArgs ) , func ) ;
}
// This function is identical to CallCDeclFunction, with the only difference that
// the value in the first parameter is the object (unless we are returning in memory)
static asQWORD CallThisCallFunction ( const void * obj , const asDWORD * pArgs , const asBYTE * pArgsType , int argSize , asDWORD func , void * retInMemory )
{
int baseArgCount = 0 ;
if ( retInMemory )
{
// the first argument is the 'return in memory' pointer
ppcArgs [ 0 ] = ( asDWORD ) retInMemory ;
ppcArgsType [ 0 ] = ppcINTARG ;
ppcArgsType [ 1 ] = ppcENDARG ;
baseArgCount = 1 ;
}
// the first argument is the 'this' of the object
ppcArgs [ baseArgCount ] = ( asDWORD ) obj ;
ppcArgsType [ baseArgCount + + ] = ppcINTARG ;
ppcArgsType [ baseArgCount ] = ppcENDARG ;
// put the arguments in the correct places in the ppcArgs array
int numTotalArgs = baseArgCount ;
if ( argSize > 0 )
{
int intArgs = baseArgCount , floatArgs = 0 , doubleArgs = 0 ;
stackArgs ( pArgs , pArgsType , intArgs , floatArgs , doubleArgs ) ;
numTotalArgs = intArgs + floatArgs + 2 * doubleArgs ; // doubles occupy two slots
}
// call the function with the arguments
return ppcFunc ( ppcArgs , PPC_STACK_SIZE ( numTotalArgs ) , func ) ;
}
// This function is identical to CallCDeclFunction, with the only difference that
// the value in the last parameter is the object
// NOTE: on PPC the order for the args is reversed
static asQWORD CallThisCallFunction_objLast ( const void * obj , const asDWORD * pArgs , const asBYTE * pArgsType , int argSize , asDWORD func , void * retInMemory )
{
UNUSED_VAR ( argSize ) ;
int baseArgCount = 0 ;
if ( retInMemory )
{
// the first argument is the 'return in memory' pointer
ppcArgs [ 0 ] = ( asDWORD ) retInMemory ;
ppcArgsType [ 0 ] = ppcINTARG ;
ppcArgsType [ 1 ] = ppcENDARG ;
baseArgCount = 1 ;
}
// stack any of the arguments
int intArgs = baseArgCount , floatArgs = 0 , doubleArgs = 0 ;
stackArgs ( pArgs , pArgsType , intArgs , floatArgs , doubleArgs ) ;
int numTotalArgs = intArgs + floatArgs + doubleArgs ;
// can we fit the object in at the end?
if ( numTotalArgs < AS_PPC_MAX_ARGS )
{
// put the object pointer at the end
int argPos = intArgs + floatArgs + ( doubleArgs * 2 ) ;
ppcArgs [ argPos ] = ( asDWORD ) obj ;
ppcArgsType [ numTotalArgs + + ] = ppcINTARG ;
ppcArgsType [ numTotalArgs ] = ppcENDARG ;
}
// call the function with the arguments
return ppcFunc ( ppcArgs , PPC_STACK_SIZE ( numTotalArgs ) , func ) ;
}
2015-05-11 19:40:43 -04:00
asQWORD CallSystemFunctionNative ( asCContext * context , asCScriptFunction * descr , void * obj , asDWORD * args , void * retPointer , asQWORD & /*retQW2*/ , void */ * secondObject */ )
2014-10-27 18:43:09 -04:00
{
2015-05-11 19:40:43 -04:00
// TODO: PPC does not yet support THISCALL_OBJFIRST/LAST
2014-10-27 18:43:09 -04:00
// use a working array of types, we'll configure the final one in stackArgs
asBYTE argsType [ 2 * AS_PPC_MAX_ARGS + 1 + 1 + 1 ] ;
memset ( argsType , 0 , sizeof ( argsType ) ) ;
asCScriptEngine * engine = context - > m_engine ;
asSSystemFunctionInterface * sysFunc = descr - > sysFuncIntf ;
asQWORD retQW = 0 ;
void * func = ( void * ) sysFunc - > func ;
int paramSize = sysFunc - > paramSize ;
asDWORD * vftable = NULL ;
int a , s ;
// convert the parameters that are < 4 bytes from little endian to big endian
int argDwordOffset = 0 ;
for ( a = 0 ; a < ( int ) descr - > parameterTypes . GetLength ( ) ; a + + )
{
int numBytes = descr - > parameterTypes [ a ] . GetSizeInMemoryBytes ( ) ;
if ( numBytes > = 4 | | descr - > parameterTypes [ a ] . IsReference ( ) | | descr - > parameterTypes [ a ] . IsObjectHandle ( ) )
{
argDwordOffset + = descr - > parameterTypes [ a ] . GetSizeOnStackDWords ( ) ;
continue ;
}
// flip
asASSERT ( numBytes = = 1 | | numBytes = = 2 ) ;
switch ( numBytes )
{
case 1 :
{
volatile asBYTE * bPtr = ( asBYTE * ) ARG_DW ( args [ argDwordOffset ] ) ;
asBYTE t = bPtr [ 0 ] ;
bPtr [ 0 ] = bPtr [ 3 ] ;
bPtr [ 3 ] = t ;
t = bPtr [ 1 ] ;
bPtr [ 1 ] = bPtr [ 2 ] ;
bPtr [ 2 ] = t ;
}
break ;
case 2 :
{
volatile asWORD * wPtr = ( asWORD * ) ARG_DW ( args [ argDwordOffset ] ) ;
asWORD t = wPtr [ 0 ] ;
wPtr [ 0 ] = wPtr [ 1 ] ;
wPtr [ 1 ] = t ;
}
break ;
}
argDwordOffset + + ;
}
// mark all float/double/int arguments
if ( ! sysFunc - > takesObjByVal )
{
for ( s = 0 , a = 0 ; s < ( int ) descr - > parameterTypes . GetLength ( ) ; s + + , a + + )
{
if ( descr - > parameterTypes [ s ] . IsFloatType ( ) & & ! descr - > parameterTypes [ s ] . IsReference ( ) )
{
argsType [ a ] = ppcFLOATARG ;
}
else if ( descr - > parameterTypes [ s ] . IsDoubleType ( ) & & ! descr - > parameterTypes [ s ] . IsReference ( ) )
{
argsType [ a ] = ppcDOUBLEARG ;
}
else
{
argsType [ a ] = ppcINTARG ;
if ( descr - > parameterTypes [ s ] . GetSizeOnStackDWords ( ) = = 2 )
{
// Add an extra integer argument for the extra size
a + + ;
argsType [ a ] = ppcINTARG ;
}
}
}
}
asDWORD paramBuffer [ 64 ] ;
if ( sysFunc - > takesObjByVal )
{
paramSize = 0 ;
int spos = 0 ;
int dpos = 1 ;
int a = 0 ;
for ( asUINT n = 0 ; n < descr - > parameterTypes . GetLength ( ) ; n + + )
{
if ( descr - > parameterTypes [ n ] . IsObject ( ) & & ! descr - > parameterTypes [ n ] . IsObjectHandle ( ) & & ! descr - > parameterTypes [ n ] . IsReference ( ) )
{
# ifdef COMPLEX_OBJS_PASSED_BY_REF
if ( descr - > parameterTypes [ n ] . GetObjectType ( ) - > flags & COMPLEX_MASK )
{
argsType [ a + + ] = ppcINTARG ;
paramBuffer [ dpos + + ] = args [ spos + + ] ;
paramSize + + ;
}
else
# endif
{
// TODO: Probably have to handle asOBJ_APP_FLOAT as a primitive
// Copy the object's memory to the buffer
memcpy ( & paramBuffer [ dpos ] , * ( void * * ) ( args + spos ) , descr - > parameterTypes [ n ] . GetSizeInMemoryBytes ( ) ) ;
// Delete the original memory
engine - > CallFree ( * ( char * * ) ( args + spos ) ) ;
spos + + ;
asUINT dwords = descr - > parameterTypes [ n ] . GetSizeInMemoryDWords ( ) ;
dpos + = dwords ;
paramSize + = dwords ;
for ( asUINT i = 0 ; i < dwords ; i + + )
argsType [ a + + ] = ppcINTARG ;
}
}
else
{
// Copy the value directly
paramBuffer [ dpos + + ] = args [ spos + + ] ;
if ( descr - > parameterTypes [ n ] . IsFloatType ( ) & & ! descr - > parameterTypes [ n ] . IsReference ( ) )
argsType [ a + + ] = ppcFLOATARG ;
else if ( descr - > parameterTypes [ n ] . IsDoubleType ( ) & & ! descr - > parameterTypes [ n ] . IsReference ( ) )
argsType [ a + + ] = ppcDOUBLEARG ;
else
argsType [ a + + ] = ppcINTARG ;
if ( descr - > parameterTypes [ n ] . GetSizeOnStackDWords ( ) > 1 )
{
paramBuffer [ dpos + + ] = args [ spos + + ] ;
if ( ! descr - > parameterTypes [ n ] . IsDoubleType ( ) ) // Double already knows it is 2 dwords
argsType [ a + + ] = ppcINTARG ;
}
paramSize + = descr - > parameterTypes [ n ] . GetSizeOnStackDWords ( ) ;
}
}
// Keep a free location at the beginning
args = & paramBuffer [ 1 ] ;
}
int callConv = sysFunc - > callConv ;
switch ( callConv )
{
case ICC_CDECL :
case ICC_CDECL_RETURNINMEM :
case ICC_STDCALL :
case ICC_STDCALL_RETURNINMEM :
retQW = CallCDeclFunction ( args , argsType , paramSize , ( asDWORD ) func , retPointer ) ;
break ;
case ICC_THISCALL :
case ICC_THISCALL_RETURNINMEM :
retQW = CallThisCallFunction ( obj , args , argsType , paramSize , ( asDWORD ) func , retPointer ) ;
break ;
case ICC_VIRTUAL_THISCALL :
case ICC_VIRTUAL_THISCALL_RETURNINMEM :
// Get virtual function table from the object pointer
vftable = * ( asDWORD * * ) obj ;
retQW = CallThisCallFunction ( obj , args , argsType , paramSize , vftable [ asDWORD ( func ) > > 2 ] , retPointer ) ;
break ;
case ICC_CDECL_OBJLAST :
case ICC_CDECL_OBJLAST_RETURNINMEM :
retQW = CallThisCallFunction_objLast ( obj , args , argsType , paramSize , ( asDWORD ) func , retPointer ) ;
break ;
case ICC_CDECL_OBJFIRST :
case ICC_CDECL_OBJFIRST_RETURNINMEM :
retQW = CallThisCallFunction ( obj , args , argsType , paramSize , ( asDWORD ) func , retPointer ) ;
break ;
default :
context - > SetInternalException ( TXT_INVALID_CALLING_CONVENTION ) ;
}
// If the return is a float value we need to get the value from the FP register
if ( sysFunc - > hostReturnFloat )
{
if ( sysFunc - > hostReturnSize = = 1 )
* ( asDWORD * ) & retQW = GetReturnedFloat ( ) ;
else
retQW = GetReturnedDouble ( ) ;
}
return retQW ;
}
END_AS_NAMESPACE
# endif // AS_PPC
# endif // AS_MAX_PORTABILITY