PageRenderTime 44ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/xbmc/visualizations/Vortex/angelscript/angelscript/source/as_callfunc_ppc.cpp

http://github.com/xbmc/xbmc
C++ | 913 lines | 643 code | 94 blank | 176 comment | 85 complexity | 58803c06c09937237e39f9a15ab48fe1 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-2.0, 0BSD, Unlicense, GPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2009 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 <stdlib.h>
  39. BEGIN_AS_NAMESPACE
  40. // This part was originally written by Pecan Heber, June 2006, for
  41. // use on MacOS X with 32bit PPC processor. He based the code on the
  42. // code in as_callfunc_sh4.cpp
  43. #define AS_PPC_MAX_ARGS 32
  44. // The array used to send values to the correct places.
  45. // Contains a byte of argTypes to indicate the register tYpe to load
  46. // or zero if end of arguments
  47. // The +1 is for when CallThis (object methods) is used
  48. // Extra +1 when returning in memory
  49. // Extra +1 in ppcArgsType to ensure zero end-of-args marker
  50. // TODO: multithread: We need to remove these global variables for thread-safety
  51. enum argTypes { ppcENDARG, ppcINTARG, ppcFLOATARG, ppcDOUBLEARG };
  52. static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1];
  53. // Using extern "C" because we use this symbol name in the assembly code
  54. extern "C"
  55. {
  56. static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
  57. }
  58. // NOTE: these values are for PowerPC 32 bit.
  59. #define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame
  60. #define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc()
  61. #define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore
  62. #define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame
  63. #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
  64. // Loads all data into the correct places and calls the function.
  65. // ppcArgsType is an array containing a byte type (enum argTypes) for each argument.
  66. // stackArgSize is the size in bytes for how much data to put on the stack frame
  67. extern "C" asQWORD ppcFunc(const asDWORD* argsPtr, int StackArgSize, asDWORD func);
  68. asm(" .text\n"
  69. " .align 2\n" // align the code to 1 << 2 = 4 bytes
  70. " .globl _ppcFunc\n"
  71. "_ppcFunc:\n"
  72. // We're receiving the following parameters
  73. // r3 : argsPtr
  74. // r4 : StackArgSize
  75. // r5 : func
  76. // The following registers are used through out the function
  77. // r31 : the address of the label address, as reference for all other labels
  78. // r30 : temporary variable
  79. // r29 : arg list pointer
  80. // r28 : number of FPR registers used by the parameters
  81. // r27 : the function pointer that will be called
  82. // r26 : the location of the parameters for the call
  83. // r25 : arg type list pointer
  84. // r24 : temporary variable
  85. // r23 : number of GPR registers used by the parameters
  86. // r1 : this is stack pointer
  87. // r0 : temporary variable
  88. // f0 : temporary variable
  89. // We need to store some of the registers for restoral before returning to caller
  90. // lr - always stored in 8(r1) - this is the return address
  91. // cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register
  92. // r1 - always stored in 0(r1) - this is the stack pointer
  93. // r11
  94. // r13 to r31
  95. // f14 to f31
  96. // Store register values and setup our stack frame
  97. " mflr r0 \n" // move the return address into r0
  98. " stw r0, 8(r1) \n" // Store the return address on the stack
  99. " stmw r23, -36(r1) \n" // Store registers r23 to r31 on the stack
  100. " stwux r1, r1, r4 \n" // Increase the stack with the needed space and store the original value in the destination
  101. // Obtain an address that we'll use as our position of reference when obtaining addresses of other labels
  102. " bl address \n"
  103. "address: \n"
  104. " mflr r31 \n"
  105. // initial registers for the function
  106. " mr r29, r3 \n" // (r29) args list
  107. " mr r27, r5 \n" // load the function pointer to call. func actually holds the pointer to our function
  108. " addi r26, r1, 24 \n" // setup the pointer to the parameter area to the function we're going to call
  109. " sub r0, r0, r0 \n" // zero out r0
  110. " mr r23, r0 \n" // zero out r23, which holds the number of used GPR registers
  111. " mr r28, r0 \n" // zero our r22, which holds the number of used float registers
  112. // load the global ppcArgsType which holds the types of arguments for each argument
  113. " addis r25, r31, ha16(_ppcArgsType - address) \n" // load the upper 16 bits of the address to r25
  114. " la r25, lo16(_ppcArgsType - address)(r25) \n" // load the lower 16 bits of the address to r25
  115. " subi r25, r25, 1 \n" // since we increment r25 on its use, we'll pre-decrement it
  116. // loop through the arguments
  117. "ppcNextArg: \n"
  118. " addi r25, r25, 1 \n" // increment r25, our arg type pointer
  119. // switch based on the current argument type (0:end, 1:int, 2:float 3:double)
  120. " lbz r24, 0(r25) \n" // load the current argument type (it's a byte)
  121. " mulli r24, r24, 4 \n" // our jump table has 4 bytes per case (1 instruction)
  122. " addis r30, r31, ha16(ppcTypeSwitch - address) \n" // load the address of the jump table for the switch
  123. " la r30, lo16(ppcTypeSwitch - address)(r30) \n"
  124. " add r0, r30, r24 \n" // offset by our argument type
  125. " mtctr r0 \n" // load the jump address into CTR
  126. " bctr \n" // jump into the jump table/switch
  127. " nop \n"
  128. // the jump table/switch based on the current argument type
  129. "ppcTypeSwitch: \n"
  130. " b ppcArgsEnd \n"
  131. " b ppcArgIsInteger \n"
  132. " b ppcArgIsFloat \n"
  133. " b ppcArgIsDouble \n"
  134. // when we get here we have finished processing all the arguments
  135. // everything is ready to go to call the function
  136. "ppcArgsEnd: \n"
  137. " mtctr r27 \n" // the function pointer is stored in r27, load that into CTR
  138. " bctrl \n" // call the function. We have to do it this way so that the LR gets the proper
  139. " nop \n" // return value (the next instruction below). So we have to branch from CTR instead of LR.
  140. // Restore registers and caller's stack frame, then return to caller
  141. " lwz r1, 0(r1) \n" // restore the caller's stack pointer
  142. " lwz r0, 8(r1) \n" // load in the caller's LR
  143. " mtlr r0 \n" // restore the caller's LR
  144. " lmw r23, -36(r1) \n" // restore registers r23 to r31 from the stack
  145. " blr \n" // return back to the caller
  146. " nop \n"
  147. // Integer argument (GPR register)
  148. "ppcArgIsInteger: \n"
  149. " addis r30, r31, ha16(ppcLoadIntReg - address) \n" // load the address to the jump table for integer registers
  150. " la r30, lo16(ppcLoadIntReg - address)(r30) \n"
  151. " mulli r0, r23, 8 \n" // each item in the jump table is 2 instructions (8 bytes)
  152. " add r0, r0, r30 \n" // calculate ppcLoadIntReg[numUsedGPRRegs]
  153. " lwz r30, 0(r29) \n" // load the next argument from the argument list into r30
  154. " cmpwi r23, 8 \n" // we can only load GPR3 through GPR10 (8 registers)
  155. " bgt ppcLoadIntRegUpd \n" // if we're beyond 8 GPR registers, we're in the stack, go there
  156. " mtctr r0 \n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers)
  157. " bctr \n" // load the argument into a GPR register
  158. " nop \n"
  159. // jump table for GPR registers, for the first 8 GPR arguments
  160. "ppcLoadIntReg: \n"
  161. " mr r3, r30 \n" // arg0 (to r3)
  162. " b ppcLoadIntRegUpd \n"
  163. " mr r4, r30 \n" // arg1 (to r4)
  164. " b ppcLoadIntRegUpd \n"
  165. " mr r5, r30 \n" // arg2 (to r5)
  166. " b ppcLoadIntRegUpd \n"
  167. " mr r6, r30 \n" // arg3 (to r6)
  168. " b ppcLoadIntRegUpd \n"
  169. " mr r7, r30 \n" // arg4 (to r7)
  170. " b ppcLoadIntRegUpd \n"
  171. " mr r8, r30 \n" // arg5 (to r8)
  172. " b ppcLoadIntRegUpd \n"
  173. " mr r9, r30 \n" // arg6 (to r9)
  174. " b ppcLoadIntRegUpd \n"
  175. " mr r10, r30 \n" // arg7 (to r10)
  176. " b ppcLoadIntRegUpd \n"
  177. // all GPR arguments still go on the stack
  178. "ppcLoadIntRegUpd: \n"
  179. " stw r30, 0(r26) \n" // store the argument into the next slot on the stack's argument list
  180. " addi r23, r23, 1 \n" // count a used GPR register
  181. " addi r29, r29, 4 \n" // move to the next argument on the list
  182. " addi r26, r26, 4 \n" // adjust our argument stack pointer for the next
  183. " b ppcNextArg \n" // next argument
  184. // single Float argument
  185. "ppcArgIsFloat:\n"
  186. " addis r30, r31, ha16(ppcLoadFloatReg - address) \n" // get the base address of the float register jump table
  187. " la r30, lo16(ppcLoadFloatReg - address)(r30) \n"
  188. " mulli r0, r28, 8 \n" // each jump table entry is 8 bytes
  189. " add r0, r0, r30 \n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg]
  190. " lfs f0, 0(r29) \n" // load the next argument as a float into f0
  191. " cmpwi r28, 13 \n" // can't load more than 13 float/double registers
  192. " bgt ppcLoadFloatRegUpd \n" // if we're beyond 13 registers, just fall to inserting into the stack
  193. " mtctr r0 \n" // jump into the float jump table
  194. " bctr \n"
  195. " nop \n"
  196. // jump table for float registers, for the first 13 float arguments
  197. "ppcLoadFloatReg: \n"
  198. " fmr f1, f0 \n" // arg0 (f1)
  199. " b ppcLoadFloatRegUpd \n"
  200. " fmr f2, f0 \n" // arg1 (f2)
  201. " b ppcLoadFloatRegUpd \n"
  202. " fmr f3, f0 \n" // arg2 (f3)
  203. " b ppcLoadFloatRegUpd \n"
  204. " fmr f4, f0 \n" // arg3 (f4)
  205. " b ppcLoadFloatRegUpd \n"
  206. " fmr f5, f0 \n" // arg4 (f5)
  207. " b ppcLoadFloatRegUpd \n"
  208. " fmr f6, f0 \n" // arg5 (f6)
  209. " b ppcLoadFloatRegUpd \n"
  210. " fmr f7, f0 \n" // arg6 (f7)
  211. " b ppcLoadFloatRegUpd \n"
  212. " fmr f8, f0 \n" // arg7 (f8)
  213. " b ppcLoadFloatRegUpd \n"
  214. " fmr f9, f0 \n" // arg8 (f9)
  215. " b ppcLoadFloatRegUpd \n"
  216. " fmr f10, f0 \n" // arg9 (f10)
  217. " b ppcLoadFloatRegUpd \n"
  218. " fmr f11, f0 \n" // arg10 (f11)
  219. " b ppcLoadFloatRegUpd \n"
  220. " fmr f12, f0 \n" // arg11 (f12)
  221. " b ppcLoadFloatRegUpd \n"
  222. " fmr f13, f0 \n" // arg12 (f13)
  223. " b ppcLoadFloatRegUpd \n"
  224. " nop \n"
  225. // all float arguments still go on the stack
  226. "ppcLoadFloatRegUpd: \n"
  227. " stfs f0, 0(r26) \n" // store, as a single float, f0 (current argument) on to the stack argument list
  228. " addi r23, r23, 1 \n" // a float register eats up a GPR register
  229. " addi r28, r28, 1 \n" // ...and, of course, a float register
  230. " addi r29, r29, 4 \n" // move to the next argument in the list
  231. " addi r26, r26, 4 \n" // move to the next stack slot
  232. " b ppcNextArg \n" // on to the next argument
  233. " nop \n"
  234. // double Float argument
  235. "ppcArgIsDouble: \n"
  236. " addis r30, r31, ha16(ppcLoadDoubleReg - address) \n" // load the base address of the jump table for double registers
  237. " la r30, lo16(ppcLoadDoubleReg - address)(r30) \n"
  238. " mulli r0, r28, 8 \n" // each slot of the jump table is 8 bytes
  239. " add r0, r0, r30 \n" // calculate ppcLoadDoubleReg[numUsedFloatReg]
  240. " lfd f0, 0(r29) \n" // load the next argument, as a double float, into f0
  241. " cmpwi r28, 13 \n" // the first 13 floats must go into float registers also
  242. " bgt ppcLoadDoubleRegUpd \n" // if we're beyond 13, then just put on to the stack
  243. " mtctr r0 \n" // we're under 13, first load our register
  244. " bctr \n" // jump into the jump table
  245. " nop \n"
  246. // jump table for float registers, for the first 13 float arguments
  247. "ppcLoadDoubleReg: \n"
  248. " fmr f1, f0 \n" // arg0 (f1)
  249. " b ppcLoadDoubleRegUpd \n"
  250. " fmr f2, f0 \n" // arg1 (f2)
  251. " b ppcLoadDoubleRegUpd \n"
  252. " fmr f3, f0 \n" // arg2 (f3)
  253. " b ppcLoadDoubleRegUpd \n"
  254. " fmr f4, f0 \n" // arg3 (f4)
  255. " b ppcLoadDoubleRegUpd \n"
  256. " fmr f5, f0 \n" // arg4 (f5)
  257. " b ppcLoadDoubleRegUpd \n"
  258. " fmr f6, f0 \n" // arg5 (f6)
  259. " b ppcLoadDoubleRegUpd \n"
  260. " fmr f7, f0 \n" // arg6 (f7)
  261. " b ppcLoadDoubleRegUpd \n"
  262. " fmr f8, f0 \n" // arg7 (f8)
  263. " b ppcLoadDoubleRegUpd \n"
  264. " fmr f9, f0 \n" // arg8 (f9)
  265. " b ppcLoadDoubleRegUpd \n"
  266. " fmr f10, f0 \n" // arg9 (f10)
  267. " b ppcLoadDoubleRegUpd \n"
  268. " fmr f11, f0 \n" // arg10 (f11)
  269. " b ppcLoadDoubleRegUpd \n"
  270. " fmr f12, f0 \n" // arg11 (f12)
  271. " b ppcLoadDoubleRegUpd \n"
  272. " fmr f13, f0 \n" // arg12 (f13)
  273. " b ppcLoadDoubleRegUpd \n"
  274. " nop \n"
  275. // all float arguments still go on the stack
  276. "ppcLoadDoubleRegUpd: \n"
  277. " stfd f0, 0(r26) \n" // store f0, as a double, into the argument list on the stack
  278. " addi r23, r23, 2 \n" // a double float eats up two GPRs
  279. " addi r28, r28, 1 \n" // ...and, of course, a float
  280. " addi r29, r29, 8 \n" // increment to our next argument we need to process (8 bytes for the 64bit float)
  281. " addi r26, r26, 8 \n" // increment to the next slot on the argument list on the stack (8 bytes)
  282. " b ppcNextArg \n" // on to the next argument
  283. " nop \n"
  284. );
  285. asDWORD GetReturnedFloat()
  286. {
  287. asDWORD f;
  288. asm(" stfs f1, %0\n" : "=m"(f));
  289. return f;
  290. }
  291. asQWORD GetReturnedDouble()
  292. {
  293. asQWORD f;
  294. asm(" stfd f1, %0\n" : "=m"(f));
  295. return f;
  296. }
  297. // puts the arguments in the correct place in the stack array. See comments above.
  298. void stackArgs(const asDWORD *args, const asBYTE *argsType, int& numIntArgs, int& numFloatArgs, int& numDoubleArgs)
  299. {
  300. int i;
  301. int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2);
  302. int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs;
  303. int typeIndex;
  304. for( i = 0, typeIndex = 0; ; i++, typeIndex++ )
  305. {
  306. // store the type
  307. ppcArgsType[typeOffset++] = argsType[typeIndex];
  308. if( argsType[typeIndex] == ppcENDARG )
  309. break;
  310. switch( argsType[typeIndex] )
  311. {
  312. case ppcFLOATARG:
  313. // stow float
  314. ppcArgs[argWordPos] = args[i]; // it's just a bit copy
  315. numFloatArgs++;
  316. argWordPos++; //add one word
  317. break;
  318. case ppcDOUBLEARG:
  319. // stow double
  320. memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment
  321. numDoubleArgs++;
  322. argWordPos+=2; //add two words
  323. i++;//doubles take up 2 argument slots
  324. break;
  325. case ppcINTARG:
  326. // stow register
  327. ppcArgs[argWordPos] = args[i];
  328. numIntArgs++;
  329. argWordPos++;
  330. break;
  331. }
  332. }
  333. // close off the argument list (if we have max args we won't close it off until here)
  334. ppcArgsType[typeOffset] = ppcENDARG;
  335. }
  336. static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
  337. {
  338. int baseArgCount = 0;
  339. if( retInMemory )
  340. {
  341. // the first argument is the 'return in memory' pointer
  342. ppcArgs[0] = (asDWORD)retInMemory;
  343. ppcArgsType[0] = ppcINTARG;
  344. ppcArgsType[1] = ppcENDARG;
  345. baseArgCount = 1;
  346. }
  347. // put the arguments in the correct places in the ppcArgs array
  348. int numTotalArgs = baseArgCount;
  349. if( argSize > 0 )
  350. {
  351. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  352. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  353. numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
  354. }
  355. else
  356. {
  357. // no arguments, cap the type list
  358. ppcArgsType[baseArgCount] = ppcENDARG;
  359. }
  360. // call the function with the arguments
  361. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
  362. }
  363. // This function is identical to CallCDeclFunction, with the only difference that
  364. // the value in the first parameter is the object (unless we are returning in memory)
  365. static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory )
  366. {
  367. int baseArgCount = 0;
  368. if( retInMemory )
  369. {
  370. // the first argument is the 'return in memory' pointer
  371. ppcArgs[0] = (asDWORD)retInMemory;
  372. ppcArgsType[0] = ppcINTARG;
  373. ppcArgsType[1] = ppcENDARG;
  374. baseArgCount = 1;
  375. }
  376. // the first argument is the 'this' of the object
  377. ppcArgs[baseArgCount] = (asDWORD)obj;
  378. ppcArgsType[baseArgCount++] = ppcINTARG;
  379. ppcArgsType[baseArgCount] = ppcENDARG;
  380. // put the arguments in the correct places in the ppcArgs array
  381. int numTotalArgs = baseArgCount;
  382. if( argSize > 0 )
  383. {
  384. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  385. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  386. numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots
  387. }
  388. // call the function with the arguments
  389. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func);
  390. }
  391. // This function is identical to CallCDeclFunction, with the only difference that
  392. // the value in the last parameter is the object
  393. // NOTE: on PPC the order for the args is reversed
  394. static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory)
  395. {
  396. UNUSED_VAR(argSize);
  397. int baseArgCount = 0;
  398. if( retInMemory )
  399. {
  400. // the first argument is the 'return in memory' pointer
  401. ppcArgs[0] = (asDWORD)retInMemory;
  402. ppcArgsType[0] = ppcINTARG;
  403. ppcArgsType[1] = ppcENDARG;
  404. baseArgCount = 1;
  405. }
  406. // stack any of the arguments
  407. int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0;
  408. stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs );
  409. int numTotalArgs = intArgs + floatArgs + doubleArgs;
  410. // can we fit the object in at the end?
  411. if( numTotalArgs < AS_PPC_MAX_ARGS )
  412. {
  413. // put the object pointer at the end
  414. int argPos = intArgs + floatArgs + (doubleArgs * 2);
  415. ppcArgs[argPos] = (asDWORD)obj;
  416. ppcArgsType[numTotalArgs++] = ppcINTARG;
  417. ppcArgsType[numTotalArgs] = ppcENDARG;
  418. }
  419. // call the function with the arguments
  420. return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func );
  421. }
  422. int CallSystemFunction(int id, asCContext *context, void *objectPointer)
  423. {
  424. // use a working array of types, we'll configure the final one in stackArgs
  425. asBYTE argsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1];
  426. memset( argsType, 0, sizeof(argsType));
  427. asCScriptEngine *engine = context->engine;
  428. asCScriptFunction *descr = engine->scriptFunctions[id];
  429. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  430. int callConv = sysFunc->callConv;
  431. if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
  432. {
  433. // we're only handling native calls, handle generic calls in here
  434. return context->CallGeneric( id, objectPointer);
  435. }
  436. asQWORD retQW = 0;
  437. void *func = (void*)sysFunc->func;
  438. int paramSize = sysFunc->paramSize;
  439. int popSize = paramSize;
  440. asDWORD *args = context->regs.stackPointer;
  441. void *obj = NULL;
  442. asDWORD *vftable = NULL;
  443. void *retObjPointer = NULL; // for system functions that return AngelScript objects
  444. void *retInMemPointer = NULL; // for host functions that need to return data in memory instead of by register
  445. int a, s;
  446. // convert the parameters that are < 4 bytes from little endian to big endian
  447. int argDwordOffset = 0;
  448. // if this is a THISCALL function and no object pointer was given, then the
  449. // first argument on the stack is the object pointer -- we MUST skip it for doing
  450. // the endian flipping.
  451. if( ( callConv >= ICC_THISCALL ) && (objectPointer == NULL) )
  452. {
  453. ++argDwordOffset;
  454. }
  455. for( a = 0; a < (int)descr->parameterTypes.GetLength(); a++ )
  456. {
  457. int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes();
  458. if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() )
  459. {
  460. argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords();
  461. continue;
  462. }
  463. // flip
  464. asASSERT( numBytes == 1 || numBytes == 2 );
  465. switch( numBytes )
  466. {
  467. case 1:
  468. {
  469. volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]);
  470. asBYTE t = bPtr[0];
  471. bPtr[0] = bPtr[3];
  472. bPtr[3] = t;
  473. t = bPtr[1];
  474. bPtr[1] = bPtr[2];
  475. bPtr[2] = t;
  476. }
  477. break;
  478. case 2:
  479. {
  480. volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]);
  481. asWORD t = wPtr[0];
  482. wPtr[0] = wPtr[1];
  483. wPtr[1] = t;
  484. }
  485. break;
  486. }
  487. argDwordOffset++;
  488. }
  489. // Objects returned to AngelScript must be via an object pointer. This goes for
  490. // ALL objects, including those of simple, complex, primitive or float. Whether
  491. // the host system (PPC in this case) returns the 'object' as a pointer depends on the type of object.
  492. context->regs.objectType = descr->returnType.GetObjectType();
  493. if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
  494. {
  495. // Allocate the memory for the object
  496. retObjPointer = engine->CallAlloc( descr->returnType.GetObjectType() );
  497. if( sysFunc->hostReturnInMemory )
  498. {
  499. // The return is made in memory on the host system
  500. callConv++;
  501. retInMemPointer = retObjPointer;
  502. }
  503. }
  504. // make sure that host functions that will be returning in memory have a memory pointer
  505. asASSERT( sysFunc->hostReturnInMemory==false || retInMemPointer!=NULL );
  506. if( callConv >= ICC_THISCALL )
  507. {
  508. if( objectPointer )
  509. {
  510. obj = objectPointer;
  511. }
  512. else
  513. {
  514. // The object pointer should be popped from the context stack
  515. popSize++;
  516. // Check for null pointer
  517. obj = (void*)*(args);
  518. if( obj == NULL )
  519. {
  520. context->SetInternalException(TXT_NULL_POINTER_ACCESS);
  521. if( retObjPointer )
  522. {
  523. engine->CallFree(retObjPointer);
  524. }
  525. return 0;
  526. }
  527. // Add the base offset for multiple inheritance
  528. obj = (void*)(int(obj) + sysFunc->baseOffset);
  529. // Skip the object pointer
  530. args++;
  531. }
  532. }
  533. asASSERT( descr->parameterTypes.GetLength() <= AS_PPC_MAX_ARGS );
  534. // mark all float/double/int arguments
  535. for( s = 0, a = 0; s < (int)descr->parameterTypes.GetLength(); s++, a++ )
  536. {
  537. if( descr->parameterTypes[s].IsFloatType() && !descr->parameterTypes[s].IsReference() )
  538. {
  539. argsType[a] = ppcFLOATARG;
  540. }
  541. else if( descr->parameterTypes[s].IsDoubleType() && !descr->parameterTypes[s].IsReference() )
  542. {
  543. argsType[a] = ppcDOUBLEARG;
  544. }
  545. else
  546. {
  547. argsType[a] = ppcINTARG;
  548. if( descr->parameterTypes[s].GetSizeOnStackDWords() == 2 )
  549. {
  550. // Add an extra integer argument for the extra size
  551. a++;
  552. argsType[a] = ppcINTARG;
  553. }
  554. }
  555. }
  556. asDWORD paramBuffer[64];
  557. if( sysFunc->takesObjByVal )
  558. {
  559. paramSize = 0;
  560. int spos = 0;
  561. int dpos = 1;
  562. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  563. {
  564. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  565. {
  566. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  567. if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
  568. {
  569. paramBuffer[dpos++] = args[spos++];
  570. paramSize++;
  571. }
  572. else
  573. #endif
  574. {
  575. // NOTE: we may have to do endian flipping here
  576. // Copy the object's memory to the buffer
  577. memcpy( &paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() );
  578. // Delete the original memory
  579. engine->CallFree(*(char**)(args+spos) );
  580. spos++;
  581. dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  582. paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
  583. }
  584. }
  585. else
  586. {
  587. // Copy the value directly
  588. paramBuffer[dpos++] = args[spos++];
  589. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  590. {
  591. paramBuffer[dpos++] = args[spos++];
  592. }
  593. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  594. }
  595. }
  596. // Keep a free location at the beginning
  597. args = &paramBuffer[1];
  598. }
  599. // one last verification to make sure things are how we expect
  600. asASSERT( (retInMemPointer!=NULL && sysFunc->hostReturnInMemory) || (retInMemPointer==NULL && !sysFunc->hostReturnInMemory) );
  601. context->isCallingSystemFunction = true;
  602. switch( callConv )
  603. {
  604. case ICC_CDECL:
  605. case ICC_CDECL_RETURNINMEM:
  606. case ICC_STDCALL:
  607. case ICC_STDCALL_RETURNINMEM:
  608. retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retInMemPointer );
  609. break;
  610. case ICC_THISCALL:
  611. case ICC_THISCALL_RETURNINMEM:
  612. retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retInMemPointer );
  613. break;
  614. case ICC_VIRTUAL_THISCALL:
  615. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  616. // Get virtual function table from the object pointer
  617. vftable = *(asDWORD**)obj;
  618. retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retInMemPointer );
  619. break;
  620. case ICC_CDECL_OBJLAST:
  621. case ICC_CDECL_OBJLAST_RETURNINMEM:
  622. retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retInMemPointer );
  623. break;
  624. case ICC_CDECL_OBJFIRST:
  625. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  626. retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retInMemPointer );
  627. break;
  628. default:
  629. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  630. }
  631. context->isCallingSystemFunction = false;
  632. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  633. if( sysFunc->takesObjByVal )
  634. {
  635. // Need to free the complex objects passed by value
  636. args = context->regs.stackPointer;
  637. if( callConv >= ICC_THISCALL && !objectPointer )
  638. args++;
  639. int spos = 0;
  640. for( int n = 0; n < (int)descr->parameterTypes.GetLength(); n++ )
  641. {
  642. if( descr->parameterTypes[n].IsObject() &&
  643. !descr->parameterTypes[n].IsReference() &&
  644. (descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
  645. {
  646. void *obj = (void*)args[spos++];
  647. asSTypeBehaviour *beh = &descr->parameterTypes[n].GetObjectType()->beh;
  648. if( beh->destruct )
  649. {
  650. engine->CallObjectMethod(obj, beh->destruct);
  651. }
  652. engine->CallFree(obj);
  653. }
  654. else
  655. {
  656. spos += descr->parameterTypes[n].GetSizeOnStackDWords();
  657. }
  658. }
  659. }
  660. #endif
  661. // Store the returned value in our stack
  662. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  663. {
  664. if( descr->returnType.IsObjectHandle() )
  665. {
  666. // Since we're treating the system function as if it is returning a QWORD we are
  667. // actually receiving the value in the high DWORD of retQW.
  668. retQW >>= 32;
  669. // returning an object handle
  670. context->regs.objectRegister = (void*)(asDWORD)retQW;
  671. if( sysFunc->returnAutoHandle && context->regs.objectRegister )
  672. {
  673. engine->CallObjectMethod(context->regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
  674. }
  675. }
  676. else
  677. {
  678. // returning an object
  679. if( !sysFunc->hostReturnInMemory )
  680. {
  681. // In this case, AngelScript wants an object pointer back, but the host system
  682. // didn't use 'return in memory', so its results were passed back by the return register.
  683. // We have have to take the results of the return register and store them IN the pointer for the object.
  684. // The data for the object could fit into a register; we need to copy that data to the object pointer's
  685. // memory.
  686. asASSERT( retInMemPointer == NULL );
  687. asASSERT( retObjPointer != NULL );
  688. // Copy the returned value to the pointer sent by the script engine
  689. if( sysFunc->hostReturnSize == 1 )
  690. {
  691. // Since we're treating the system function as if it is returning a QWORD we are
  692. // actually receiving the value in the high DWORD of retQW.
  693. retQW >>= 32;
  694. *(asDWORD*)retObjPointer = (asDWORD)retQW;
  695. }
  696. else
  697. {
  698. *(asQWORD*)retObjPointer = retQW;
  699. }
  700. }
  701. else
  702. {
  703. // In this case, AngelScript wants an object pointer back, and the host system
  704. // used 'return in memory'. So its results were already passed back in memory, and
  705. // stored in the object pointer.
  706. asASSERT( retInMemPointer != NULL );
  707. asASSERT( retObjPointer != NULL );
  708. }
  709. // store the return results into the object register
  710. context->regs.objectRegister = retObjPointer;
  711. }
  712. }
  713. else
  714. {
  715. // Store value in valueRegister
  716. if( sysFunc->hostReturnFloat )
  717. {
  718. // floating pointer primitives
  719. if( sysFunc->hostReturnSize == 1 )
  720. {
  721. // single float
  722. *(asDWORD*)&context->regs.valueRegister = GetReturnedFloat();
  723. }
  724. else
  725. {
  726. // double float
  727. context->regs.valueRegister = GetReturnedDouble();
  728. }
  729. }
  730. else if( sysFunc->hostReturnSize == 1 )
  731. {
  732. // <= 32 bit primitives
  733. // Since we're treating the system function as if it is returning a QWORD we are
  734. // actually receiving the value in the high DWORD of retQW.
  735. retQW >>= 32;
  736. // due to endian issues we need to handle return values, that are
  737. // less than a DWORD (32 bits) in size, special
  738. int numBytes = descr->returnType.GetSizeInMemoryBytes();
  739. if( descr->returnType.IsReference() ) numBytes = 4;
  740. switch( numBytes )
  741. {
  742. case 1:
  743. {
  744. // 8 bits
  745. asBYTE *val = (asBYTE*)ARG_DW(context->regs.valueRegister);
  746. val[0] = (asBYTE)retQW;
  747. val[1] = 0;
  748. val[2] = 0;
  749. val[3] = 0;
  750. val[4] = 0;
  751. val[5] = 0;
  752. val[6] = 0;
  753. val[7] = 0;
  754. }
  755. break;
  756. case 2:
  757. {
  758. // 16 bits
  759. asWORD *val = (asWORD*)ARG_DW(context->regs.valueRegister);
  760. val[0] = (asWORD)retQW;
  761. val[1] = 0;
  762. val[2] = 0;
  763. val[3] = 0;
  764. }
  765. break;
  766. default:
  767. {
  768. // 32 bits
  769. asDWORD *val = (asDWORD*)ARG_DW(context->regs.valueRegister);
  770. val[0] = (asDWORD)retQW;
  771. val[1] = 0;
  772. }
  773. break;
  774. }
  775. }
  776. else
  777. {
  778. // 64 bit primitive
  779. context->regs.valueRegister = retQW;
  780. }
  781. }
  782. if( sysFunc->hasAutoHandles )
  783. {
  784. args = context->regs.stackPointer;
  785. if( callConv >= ICC_THISCALL && !objectPointer )
  786. {
  787. args++;
  788. }
  789. int spos = 0;
  790. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  791. {
  792. if( sysFunc->paramAutoHandles[n] && args[spos] )
  793. {
  794. // Call the release method on the type
  795. engine->CallObjectMethod((void*)args[spos], descr->parameterTypes[n].GetObjectType()->beh.release);
  796. args[spos] = 0;
  797. }
  798. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  799. {
  800. spos++;
  801. }
  802. else
  803. {
  804. spos += descr->parameterTypes[n].GetSizeOnStackDWords();
  805. }
  806. }
  807. }
  808. return popSize;
  809. }
  810. END_AS_NAMESPACE
  811. #endif // AS_PPC
  812. #endif // AS_MAX_PORTABILITY