as_callfunc_ppc.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2015 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_callfunc_ppc.cpp
  25. //
  26. // These functions handle the actual calling of system functions
  27. //
  28. // This version is PPC specific
  29. //
  30. #include <stdio.h>
  31. #include "as_config.h"
  32. #ifndef AS_MAX_PORTABILITY
  33. #ifdef AS_PPC
  34. #include "as_callfunc.h"
  35. #include "as_scriptengine.h"
  36. #include "as_texts.h"
  37. #include "as_tokendef.h"
  38. #include "as_context.h"
  39. #include <stdlib.h>
  40. BEGIN_AS_NAMESPACE
  41. // This part was originally written by Pecan Heber, June 2006, for
  42. // use on MacOS X with 32bit PPC processor. He based the code on the
  43. // code in as_callfunc_sh4.cpp
  44. #define AS_PPC_MAX_ARGS 32
  45. // The array used to send values to the correct places.
  46. // Contains a byte of argTypes to indicate the register tYpe to load
  47. // or zero if end of arguments
  48. // The +1 is for when CallThis (object methods) is used
  49. // Extra +1 when returning in memory
  50. // Extra +1 in ppcArgsType to ensure zero end-of-args marker
  51. // TODO: multithread: We need to remove these global variables for thread-safety
  52. enum argTypes { ppcENDARG, ppcINTARG, ppcFLOATARG, ppcDOUBLEARG };
  53. static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1];
  54. // Using extern "C" because we use this symbol name in the assembly code
  55. extern "C"
  56. {
  57. static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
  58. }
  59. // NOTE: these values are for PowerPC 32 bit.
  60. #define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame
  61. #define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc()
  62. #define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore
  63. #define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame
  64. #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
  65. // Loads all data into the correct places and calls the function.
  66. // ppcArgsType is an array containing a byte type (enum argTypes) for each argument.
  67. // stackArgSize is the size in bytes for how much data to put on the stack frame
  68. extern "C" asQWORD ppcFunc(const asDWORD* argsPtr, int StackArgSize, asDWORD func);
  69. asm(" .text\n"
  70. " .align 2\n" // align the code to 1 << 2 = 4 bytes
  71. " .globl _ppcFunc\n"
  72. "_ppcFunc:\n"
  73. // We're receiving the following parameters
  74. // r3 : argsPtr
  75. // r4 : StackArgSize
  76. // r5 : func
  77. // The following registers are used through out the function
  78. // r31 : the address of the label address, as reference for all other labels
  79. // r30 : temporary variable
  80. // r29 : arg list pointer
  81. // r28 : number of FPR registers used by the parameters
  82. // r27 : the function pointer that will be called
  83. // r26 : the location of the parameters for the call
  84. // r25 : arg type list pointer
  85. // r24 : temporary variable
  86. // r23 : number of GPR registers used by the parameters
  87. // r1 : this is stack pointer
  88. // r0 : temporary variable
  89. // f0 : temporary variable
  90. // We need to store some of the registers for restoral before returning to caller
  91. // lr - always stored in 8(r1) - this is the return address
  92. // cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register
  93. // r1 - always stored in 0(r1) - this is the stack pointer
  94. // r11
  95. // r13 to r31
  96. // f14 to f31
  97. // Store register values and setup our stack frame
  98. " mflr r0 \n" // move the return address into r0
  99. " stw r0, 8(r1) \n" // Store the return address on the stack
  100. " stmw r23, -36(r1) \n" // Store registers r23 to r31 on the stack
  101. " stwux r1, r1, r4 \n" // Increase the stack with the needed space and store the original value in the destination
  102. // Obtain an address that we'll use as our position of reference when obtaining addresses of other labels
  103. " bl address \n"
  104. "address: \n"
  105. " mflr r31 \n"
  106. // initial registers for the function
  107. " mr r29, r3 \n" // (r29) args list
  108. " mr r27, r5 \n" // load the function pointer to call. func actually holds the pointer to our function
  109. " addi r26, r1, 24 \n" // setup the pointer to the parameter area to the function we're going to call
  110. " sub r0, r0, r0 \n" // zero out r0
  111. " mr r23, r0 \n" // zero out r23, which holds the number of used GPR registers
  112. " mr r28, r0 \n" // zero our r22, which holds the number of used float registers
  113. // load the global ppcArgsType which holds the types of arguments for each argument
  114. " addis r25, r31, ha16(_ppcArgsType - address) \n" // load the upper 16 bits of the address to r25
  115. " la r25, lo16(_ppcArgsType - address)(r25) \n" // load the lower 16 bits of the address to r25
  116. " subi r25, r25, 1 \n" // since we increment r25 on its use, we'll pre-decrement it
  117. // loop through the arguments
  118. "ppcNextArg: \n"
  119. " addi r25, r25, 1 \n" // increment r25, our arg type pointer
  120. // switch based on the current argument type (0:end, 1:int, 2:float 3:double)
  121. " lbz r24, 0(r25) \n" // load the current argument type (it's a byte)
  122. " mulli r24, r24, 4 \n" // our jump table has 4 bytes per case (1 instruction)
  123. " addis r30, r31, ha16(ppcTypeSwitch - address) \n" // load the address of the jump table for the switch
  124. " la r30, lo16(ppcTypeSwitch - address)(r30) \n"
  125. " add r0, r30, r24 \n" // offset by our argument type
  126. " mtctr r0 \n" // load the jump address into CTR
  127. " bctr \n" // jump into the jump table/switch
  128. " nop \n"
  129. // the jump table/switch based on the current argument type
  130. "ppcTypeSwitch: \n"
  131. " b ppcArgsEnd \n"
  132. " b ppcArgIsInteger \n"
  133. " b ppcArgIsFloat \n"
  134. " b ppcArgIsDouble \n"
  135. // when we get here we have finished processing all the arguments
  136. // everything is ready to go to call the function
  137. "ppcArgsEnd: \n"
  138. " mtctr r27 \n" // the function pointer is stored in r27, load that into CTR
  139. " bctrl \n" // call the function. We have to do it this way so that the LR gets the proper
  140. " nop \n" // return value (the next instruction below). So we have to branch from CTR instead of LR.
  141. // Restore registers and caller's stack frame, then return to caller
  142. " lwz r1, 0(r1) \n" // restore the caller's stack pointer
  143. " lwz r0, 8(r1) \n" // load in the caller's LR
  144. " mtlr r0 \n" // restore the caller's LR
  145. " lmw r23, -36(r1) \n" // restore registers r23 to r31 from the stack
  146. " blr \n" // return back to the caller
  147. " nop \n"
  148. // Integer argument (GPR register)
  149. "ppcArgIsInteger: \n"
  150. " addis r30, r31, ha16(ppcLoadIntReg - address) \n" // load the address to the jump table for integer registers
  151. " la r30, lo16(ppcLoadIntReg - address)(r30) \n"
  152. " mulli r0, r23, 8 \n" // each item in the jump table is 2 instructions (8 bytes)
  153. " add r0, r0, r30 \n" // calculate ppcLoadIntReg[numUsedGPRRegs]
  154. " lwz r30, 0(r29) \n" // load the next argument from the argument list into r30
  155. " cmpwi r23, 8 \n" // we can only load GPR3 through GPR10 (8 registers)
  156. " bgt ppcLoadIntRegUpd \n" // if we're beyond 8 GPR registers, we're in the stack, go there
  157. " mtctr r0 \n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers)
  158. " bctr \n" // load the argument into a GPR register
  159. " nop \n"
  160. // jump table for GPR registers, for the first 8 GPR arguments
  161. "ppcLoadIntReg: \n"
  162. " mr r3, r30 \n" // arg0 (to r3)
  163. " b ppcLoadIntRegUpd \n"
  164. " mr r4, r30 \n" // arg1 (to r4)
  165. " b ppcLoadIntRegUpd \n"
  166. " mr r5, r30 \n" // arg2 (to r5)
  167. " b ppcLoadIntRegUpd \n"
  168. " mr r6, r30 \n" // arg3 (to r6)
  169. " b ppcLoadIntRegUpd \n"
  170. " mr r7, r30 \n" // arg4 (to r7)
  171. " b ppcLoadIntRegUpd \n"
  172. " mr r8, r30 \n" // arg5 (to r8)
  173. " b ppcLoadIntRegUpd \n"
  174. " mr r9, r30 \n" // arg6 (to r9)
  175. " b ppcLoadIntRegUpd \n"
  176. " mr r10, r30 \n" // arg7 (to r10)
  177. " b ppcLoadIntRegUpd \n"
  178. // all GPR arguments still go on the stack
  179. "ppcLoadIntRegUpd: \n"
  180. " stw r30, 0(r26) \n" // store the argument into the next slot on the stack's argument list
  181. " addi r23, r23, 1 \n" // count a used GPR register
  182. " addi r29, r29, 4 \n" // move to the next argument on the list
  183. " addi r26, r26, 4 \n" // adjust our argument stack pointer for the next
  184. " b ppcNextArg \n" // next argument
  185. // single Float argument
  186. "ppcArgIsFloat:\n"
  187. " addis r30, r31, ha16(ppcLoadFloatReg - address) \n" // get the base address of the float register jump table
  188. " la r30, lo16(ppcLoadFloatReg - address)(r30) \n"
  189. " mulli r0, r28, 8 \n" // each jump table entry is 8 bytes
  190. " add r0, r0, r30 \n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg]
  191. " lfs f0, 0(r29) \n" // load the next argument as a float into f0
  192. " cmpwi r28, 13 \n" // can't load more than 13 float/double registers
  193. " bgt ppcLoadFloatRegUpd \n" // if we're beyond 13 registers, just fall to inserting into the stack
  194. " mtctr r0 \n" // jump into the float jump table
  195. " bctr \n"
  196. " nop \n"
  197. // jump table for float registers, for the first 13 float arguments
  198. "ppcLoadFloatReg: \n"
  199. " fmr f1, f0 \n" // arg0 (f1)
  200. " b ppcLoadFloatRegUpd \n"
  201. " fmr f2, f0 \n" // arg1 (f2)
  202. " b ppcLoadFloatRegUpd \n"
  203. " fmr f3, f0 \n" // arg2 (f3)
  204. " b ppcLoadFloatRegUpd \n"
  205. " fmr f4, f0 \n" // arg3 (f4)
  206. " b ppcLoadFloatRegUpd \n"
  207. " fmr f5, f0 \n" // arg4 (f5)
  208. " b ppcLoadFloatRegUpd \n"
  209. " fmr f6, f0 \n" // arg5 (f6)
  210. " b ppcLoadFloatRegUpd \n"
  211. " fmr f7, f0 \n" // arg6 (f7)
  212. " b ppcLoadFloatRegUpd \n"
  213. " fmr f8, f0 \n" // arg7 (f8)
  214. " b ppcLoadFloatRegUpd \n"
  215. " fmr f9, f0 \n" // arg8 (f9)
  216. " b ppcLoadFloatRegUpd \n"
  217. " fmr f10, f0 \n" // arg9 (f10)
  218. " b ppcLoadFloatRegUpd \n"
  219. " fmr f11, f0 \n" // arg10 (f11)
  220. " b ppcLoadFloatRegUpd \n"
  221. " fmr f12, f0 \n" // arg11 (f12)
  222. " b ppcLoadFloatRegUpd \n"
  223. " fmr f13, f0 \n" // arg12 (f13)
  224. " b ppcLoadFloatRegUpd \n"
  225. " nop \n"
  226. // all float arguments still go on the stack
  227. "ppcLoadFloatRegUpd: \n"
  228. " stfs f0, 0(r26) \n" // store, as a single float, f0 (current argument) on to the stack argument list
  229. " addi r23, r23, 1 \n" // a float register eats up a GPR register
  230. " addi r28, r28, 1 \n" // ...and, of course, a float register
  231. " addi r29, r29, 4 \n" // move to the next argument in the list
  232. " addi r26, r26, 4 \n" // move to the next stack slot
  233. " b ppcNextArg \n" // on to the next argument
  234. " nop \n"
  235. // double Float argument
  236. "ppcArgIsDouble: \n"
  237. " addis r30, r31, ha16(ppcLoadDoubleReg - address) \n" // load the base address of the jump table for double registers
  238. " la r30, lo16(ppcLoadDoubleReg - address)(r30) \n"
  239. " mulli r0, r28, 8 \n" // each slot of the jump table is 8 bytes
  240. " add r0, r0, r30 \n" // calculate ppcLoadDoubleReg[numUsedFloatReg]
  241. " lfd f0, 0(r29) \n" // load the next argument, as a double float, into f0
  242. " cmpwi r28, 13 \n" // the first 13 floats must go into float registers also
  243. " bgt ppcLoadDoubleRegUpd \n" // if we're beyond 13, then just put on to the stack
  244. " mtctr r0 \n" // we're under 13, first load our register
  245. " bctr \n" // jump into the jump table
  246. " nop \n"
  247. // jump table for float registers, for the first 13 float arguments
  248. "ppcLoadDoubleReg: \n"
  249. " fmr f1, f0 \n" // arg0 (f1)
  250. " b ppcLoadDoubleRegUpd \n"
  251. " fmr f2, f0 \n" // arg1 (f2)
  252. " b ppcLoadDoubleRegUpd \n"
  253. " fmr f3, f0 \n" // arg2 (f3)
  254. " b ppcLoadDoubleRegUpd \n"
  255. " fmr f4, f0 \n" // arg3 (f4)
  256. " b ppcLoadDoubleRegUpd \n"
  257. " fmr f5, f0 \n" // arg4 (f5)
  258. " b ppcLoadDoubleRegUpd \n"
  259. " fmr f6, f0 \n" // arg5 (f6)
  260. " b ppcLoadDoubleRegUpd \n"
  261. " fmr f7, f0 \n" // arg6 (f7)
  262. " b ppcLoadDoubleRegUpd \n"
  263. " fmr f8, f0 \n" // arg7 (f8)
  264. " b ppcLoadDoubleRegUpd \n"
  265. " fmr f9, f0 \n" // arg8 (f9)
  266. " b ppcLoadDoubleRegUpd \n"
  267. " fmr f10, f0 \n" // arg9 (f10)
  268. " b ppcLoadDoubleRegUpd \n"
  269. " fmr f11, f0 \n" // arg10 (f11)
  270. " b ppcLoadDoubleRegUpd \n"
  271. " fmr f12, f0 \n" // arg11 (f12)
  272. " b ppcLoadDoubleRegUpd \n"
  273. " fmr f13, f0 \n" // arg12 (f13)
  274. " b ppcLoadDoubleRegUpd \n"
  275. " nop \n"
  276. // all float arguments still go on the stack
  277. "ppcLoadDoubleRegUpd: \n"
  278. " stfd f0, 0(r26) \n" // store f0, as a double, into the argument list on the stack
  279. " addi r23, r23, 2 \n" // a double float eats up two GPRs
  280. " addi r28, r28, 1 \n" // ...and, of course, a float
  281. " addi r29, r29, 8 \n" // increment to our next argument we need to process (8 bytes for the 64bit float)
  282. " addi r26, r26, 8 \n" // increment to the next slot on the argument list on the stack (8 bytes)
  283. " b ppcNextArg \n" // on to the next argument
  284. " nop \n"
  285. );
  286. asDWORD GetReturnedFloat()
  287. {
  288. asDWORD f;
  289. asm(" stfs f1, %0\n" : "=m"(f));
  290. return f;
  291. }
  292. asQWORD GetReturnedDouble()
  293. {
  294. asQWORD f;
  295. asm(" stfd f1, %0\n" : "=m"(f));
  296. return f;
  297. }
  298. // puts the arguments in the correct place in the stack array. See comments above.
  299. void stackArgs(const asDWORD *args, const asBYTE *argsType, int& numIntArgs, int& numFloatArgs, int& numDoubleArgs)
  300. {
  301. int i;
  302. int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2);
  303. int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs;
  304. int typeIndex;
  305. for( i = 0, typeIndex = 0; ; i++, typeIndex++ )
  306. {
  307. // store the type
  308. ppcArgsType[typeOffset++] = argsType[typeIndex];
  309. if( argsType[typeIndex] == ppcENDARG )
  310. break;
  311. switch( argsType[typeIndex] )
  312. {
  313. case ppcFLOATARG:
  314. // stow float
  315. ppcArgs[argWordPos] = args[i]; // it's just a bit copy
  316. numFloatArgs++;
  317. argWordPos++; //add one word
  318. break;
  319. case ppcDOUBLEARG:
  320. // stow double
  321. memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment
  322. numDoubleArgs++;
  323. argWordPos+=2; //add two words
  324. i++;//doubles take up 2 argument slots
  325. break;
  326. case ppcINTARG:
  327. // stow register
  328. ppcArgs[argWordPos] = args[i];
  329. numIntArgs++;
  330. argWordPos++;
  331. break;
  332. }
  333. }
  334. // close off the argument list (if we have max args we won't close it off until here)
  335. ppcArgsType[typeOffset] = ppcENDARG;
  336. }
  337. static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
  338. {
  339. int baseArgCount = 0;
  340. if( retInMemory )
  341. {
  342. // the first argument is the 'return in memory' pointer
  343. ppcArgs[0] = (asDWORD)retInMemory;
  344. ppcArgsType[0] = ppcINTARG;
  345. ppcArgsType[1] = ppcENDARG;
  346. baseArgCount = 1;
  347. }
  348. // put the arguments in the correct places in the ppcArgs array
  349. int numTotalArgs = baseArgCount;
  350. if( argSize > 0 )
  351. {
  352. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  353. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  354. numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
  355. }
  356. else
  357. {
  358. // no arguments, cap the type list
  359. ppcArgsType[baseArgCount] = ppcENDARG;
  360. }
  361. // call the function with the arguments
  362. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
  363. }
  364. // This function is identical to CallCDeclFunction, with the only difference that
  365. // the value in the first parameter is the object (unless we are returning in memory)
  366. static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory )
  367. {
  368. int baseArgCount = 0;
  369. if( retInMemory )
  370. {
  371. // the first argument is the 'return in memory' pointer
  372. ppcArgs[0] = (asDWORD)retInMemory;
  373. ppcArgsType[0] = ppcINTARG;
  374. ppcArgsType[1] = ppcENDARG;
  375. baseArgCount = 1;
  376. }
  377. // the first argument is the 'this' of the object
  378. ppcArgs[baseArgCount] = (asDWORD)obj;
  379. ppcArgsType[baseArgCount++] = ppcINTARG;
  380. ppcArgsType[baseArgCount] = ppcENDARG;
  381. // put the arguments in the correct places in the ppcArgs array
  382. int numTotalArgs = baseArgCount;
  383. if( argSize > 0 )
  384. {
  385. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  386. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  387. numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
  388. }
  389. // call the function with the arguments
  390. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func);
  391. }
  392. // This function is identical to CallCDeclFunction, with the only difference that
  393. // the value in the last parameter is the object
  394. // NOTE: on PPC the order for the args is reversed
  395. static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
  396. {
  397. UNUSED_VAR(argSize);
  398. int baseArgCount = 0;
  399. if( retInMemory )
  400. {
  401. // the first argument is the 'return in memory' pointer
  402. ppcArgs[0] = (asDWORD)retInMemory;
  403. ppcArgsType[0] = ppcINTARG;
  404. ppcArgsType[1] = ppcENDARG;
  405. baseArgCount = 1;
  406. }
  407. // stack any of the arguments
  408. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  409. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  410. int numTotalArgs = intArgs + floatArgs + doubleArgs;
  411. // can we fit the object in at the end?
  412. if( numTotalArgs < AS_PPC_MAX_ARGS )
  413. {
  414. // put the object pointer at the end
  415. int argPos = intArgs + floatArgs + (doubleArgs * 2);
  416. ppcArgs[argPos] = (asDWORD)obj;
  417. ppcArgsType[numTotalArgs++] = ppcINTARG;
  418. ppcArgsType[numTotalArgs] = ppcENDARG;
  419. }
  420. // call the function with the arguments
  421. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
  422. }
  423. asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/)
  424. {
  425. // TODO: PPC does not yet support THISCALL_OBJFIRST/LAST
  426. // use a working array of types, we'll configure the final one in stackArgs
  427. asBYTE argsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
  428. memset( argsType, 0, sizeof(argsType));
  429. asCScriptEngine *engine = context->m_engine;
  430. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  431. asQWORD retQW = 0;
  432. void *func = (void*)sysFunc->func;
  433. int paramSize = sysFunc->paramSize;
  434. asDWORD *vftable = NULL;
  435. int a, s;
  436. // convert the parameters that are < 4 bytes from little endian to big endian
  437. int argDwordOffset = 0;
  438. for( a = 0; a < (int)descr->parameterTypes.GetLength(); a++ )
  439. {
  440. int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes();
  441. if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() )
  442. {
  443. argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords();
  444. continue;
  445. }
  446. // flip
  447. asASSERT( numBytes == 1 || numBytes == 2 );
  448. switch( numBytes )
  449. {
  450. case 1:
  451. {
  452. volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]);
  453. asBYTE t = bPtr[0];
  454. bPtr[0] = bPtr[3];
  455. bPtr[3] = t;
  456. t = bPtr[1];
  457. bPtr[1] = bPtr[2];
  458. bPtr[2] = t;
  459. }
  460. break;
  461. case 2:
  462. {
  463. volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]);
  464. asWORD t = wPtr[0];
  465. wPtr[0] = wPtr[1];
  466. wPtr[1] = t;
  467. }
  468. break;
  469. }
  470. argDwordOffset++;
  471. }
  472. // mark all float/double/int arguments
  473. if( !sysFunc->takesObjByVal )
  474. {
  475. for( s = 0, a = 0; s < (int)descr->parameterTypes.GetLength(); s++, a++ )
  476. {
  477. if( descr->parameterTypes[s].IsFloatType() && !descr->parameterTypes[s].IsReference() )
  478. {
  479. argsType[a] = ppcFLOATARG;
  480. }
  481. else if( descr->parameterTypes[s].IsDoubleType() && !descr->parameterTypes[s].IsReference() )
  482. {
  483. argsType[a] = ppcDOUBLEARG;
  484. }
  485. else
  486. {
  487. argsType[a] = ppcINTARG;
  488. if( descr->parameterTypes[s].GetSizeOnStackDWords() == 2 )
  489. {
  490. // Add an extra integer argument for the extra size
  491. a++;
  492. argsType[a] = ppcINTARG;
  493. }
  494. }
  495. }
  496. }
  497. asDWORD paramBuffer[64];
  498. if( sysFunc->takesObjByVal )
  499. {
  500. paramSize = 0;
  501. int spos = 0;
  502. int dpos = 1;
  503. int a = 0;
  504. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  505. {
  506. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  507. {
  508. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  509. if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
  510. {
  511. argsType[a++] = ppcINTARG;
  512. paramBuffer[dpos++] = args[spos++];
  513. paramSize++;
  514. }
  515. else
  516. #endif
  517. {
  518. // TODO: Probably have to handle asOBJ_APP_FLOAT as a primitive
  519. // Copy the object's memory to the buffer
  520. memcpy( &paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() );
  521. // Delete the original memory
  522. engine->CallFree(*(char**)(args+spos) );
  523. spos++;
  524. asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords();
  525. dpos += dwords;
  526. paramSize += dwords;
  527. for( asUINT i = 0; i < dwords; i++ )
  528. argsType[a++] = ppcINTARG;
  529. }
  530. }
  531. else
  532. {
  533. // Copy the value directly
  534. paramBuffer[dpos++] = args[spos++];
  535. if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() )
  536. argsType[a++] = ppcFLOATARG;
  537. else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() )
  538. argsType[a++] = ppcDOUBLEARG;
  539. else
  540. argsType[a++] = ppcINTARG;
  541. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  542. {
  543. paramBuffer[dpos++] = args[spos++];
  544. if( !descr->parameterTypes[n].IsDoubleType() ) // Double already knows it is 2 dwords
  545. argsType[a++] = ppcINTARG;
  546. }
  547. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  548. }
  549. }
  550. // Keep a free location at the beginning
  551. args = &paramBuffer[1];
  552. }
  553. int callConv = sysFunc->callConv;
  554. switch( callConv )
  555. {
  556. case ICC_CDECL:
  557. case ICC_CDECL_RETURNINMEM:
  558. case ICC_STDCALL:
  559. case ICC_STDCALL_RETURNINMEM:
  560. retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer );
  561. break;
  562. case ICC_THISCALL:
  563. case ICC_THISCALL_RETURNINMEM:
  564. retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer );
  565. break;
  566. case ICC_VIRTUAL_THISCALL:
  567. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  568. // Get virtual function table from the object pointer
  569. vftable = *(asDWORD**)obj;
  570. retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer );
  571. break;
  572. case ICC_CDECL_OBJLAST:
  573. case ICC_CDECL_OBJLAST_RETURNINMEM:
  574. retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
  575. break;
  576. case ICC_CDECL_OBJFIRST:
  577. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  578. retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer );
  579. break;
  580. default:
  581. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  582. }
  583. // If the return is a float value we need to get the value from the FP register
  584. if( sysFunc->hostReturnFloat )
  585. {
  586. if( sysFunc->hostReturnSize == 1 )
  587. *(asDWORD*)&retQW = GetReturnedFloat();
  588. else
  589. retQW = GetReturnedDouble();
  590. }
  591. return retQW;
  592. }
  593. END_AS_NAMESPACE
  594. #endif // AS_PPC
  595. #endif // AS_MAX_PORTABILITY