as_callfunc_x86.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2018 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_x86.cpp
  25. //
  26. // These functions handle the actual calling of system functions
  27. //
  28. // Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
  29. //
  30. #include "as_config.h"
  31. #ifndef AS_MAX_PORTABILITY
  32. #ifdef AS_X86
  33. #include "as_callfunc.h"
  34. #include "as_scriptengine.h"
  35. #include "as_texts.h"
  36. #include "as_tokendef.h"
  37. #include "as_context.h"
  38. BEGIN_AS_NAMESPACE
  39. //
  40. // With some compile level optimizations the functions don't clear the FPU
  41. // stack themselves. So we have to do it as part of calling the native functions,
  42. // as the compiler will not be able to predict when it is supposed to do it by
  43. // itself due to the dynamic nature of scripts
  44. //
  45. // - fninit clears the FPU stack and the FPU control word
  46. // - emms only clears the FPU stack, while preserving the FPU control word
  47. //
  48. // By default I use fninit as it seems to be what works for most people,
  49. // but some may find it necessary to define this as emms instead.
  50. //
  51. // TODO: Figure out when one or the other must be used, and a way to
  52. // configure this automatically in as_config.h
  53. //
  54. #ifndef CLEAR_FPU_STACK
  55. #define CLEAR_FPU_STACK fninit
  56. #endif
  57. // These macros are just to allow me to use the above macro in the GNUC style inline assembly
  58. #define _S(x) _TOSTRING(x)
  59. #define _TOSTRING(x) #x
  60. // Prototypes
  61. asQWORD CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
  62. asQWORD CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  63. asQWORD CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  64. asQWORD CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  65. asQWORD CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  66. asQWORD CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
  67. asQWORD CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
  68. asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
  69. asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr);
  70. asDWORD GetReturnedFloat();
  71. asQWORD GetReturnedDouble();
  72. asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
  73. {
  74. asCScriptEngine *engine = context->m_engine;
  75. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  76. asQWORD retQW = 0;
  77. // Prepare the parameters
  78. asDWORD paramBuffer[64];
  79. int callConv = sysFunc->callConv;
  80. // Changed because need check for ICC_THISCALL_OBJFIRST or
  81. // ICC_THISCALL_OBJLAST if sysFunc->takesObjByVal (avoid copy code)
  82. // Check if is THISCALL_OBJ* calling convention (in this case needs to add secondObject pointer into stack).
  83. bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
  84. int paramSize = isThisCallMethod || sysFunc->takesObjByVal ? 0 : sysFunc->paramSize;
  85. int dpos = 1;
  86. if( isThisCallMethod &&
  87. (callConv >= ICC_THISCALL_OBJFIRST &&
  88. callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
  89. {
  90. // Add the object pointer as the first parameter
  91. paramBuffer[dpos++] = (asDWORD)secondObject;
  92. paramSize++;
  93. }
  94. if( sysFunc->takesObjByVal || isThisCallMethod )
  95. {
  96. int spos = 0;
  97. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  98. {
  99. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  100. {
  101. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  102. if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
  103. {
  104. paramBuffer[dpos++] = args[spos++];
  105. paramSize++;
  106. }
  107. else
  108. #endif
  109. {
  110. // Copy the object's memory to the buffer
  111. // TODO: bug: Must call the object's copy constructor instead of doing a memcpy,
  112. // as the object may hold a pointer to itself. It's not enough to
  113. // change only this memcpy as the assembler routine also makes a copy
  114. // of paramBuffer to the final stack location. To avoid the second
  115. // copy the C++ routine should point paramBuffer to the final stack
  116. // position and copy the values directly to that location. The assembler
  117. // routines then don't need to copy anything, and will just be
  118. // responsible for setting up the registers and the stack frame appropriately.
  119. memcpy(&paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
  120. // Delete the original memory
  121. engine->CallFree(*(char**)(args+spos));
  122. spos++;
  123. dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  124. paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
  125. }
  126. }
  127. else
  128. {
  129. // Copy the value directly
  130. paramBuffer[dpos++] = args[spos++];
  131. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  132. paramBuffer[dpos++] = args[spos++];
  133. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  134. }
  135. }
  136. // Keep a free location at the beginning
  137. args = &paramBuffer[1];
  138. }
  139. if( isThisCallMethod &&
  140. (callConv >= ICC_THISCALL_OBJLAST &&
  141. callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
  142. {
  143. // Add the object pointer as the last parameter
  144. paramBuffer[dpos++] = (asDWORD)secondObject;
  145. paramSize++;
  146. }
  147. // Make the actual call
  148. asFUNCTION_t func = sysFunc->func;
  149. if( sysFunc->hostReturnInMemory )
  150. callConv++;
  151. switch( callConv )
  152. {
  153. case ICC_CDECL:
  154. retQW = CallCDeclFunction(args, paramSize<<2, func);
  155. break;
  156. case ICC_CDECL_RETURNINMEM:
  157. retQW = CallCDeclFunctionRetByRef(args, paramSize<<2, func, retPointer);
  158. break;
  159. case ICC_STDCALL:
  160. retQW = CallSTDCallFunction(args, paramSize<<2, func);
  161. break;
  162. case ICC_STDCALL_RETURNINMEM:
  163. // Push the return pointer on the stack
  164. paramSize++;
  165. args--;
  166. *(asPWORD*)args = (size_t)retPointer;
  167. retQW = CallSTDCallFunction(args, paramSize<<2, func);
  168. break;
  169. case ICC_THISCALL:
  170. case ICC_THISCALL_OBJFIRST:
  171. case ICC_THISCALL_OBJLAST:
  172. retQW = CallThisCallFunction(obj, args, paramSize<<2, func);
  173. break;
  174. case ICC_THISCALL_RETURNINMEM:
  175. case ICC_THISCALL_OBJFIRST_RETURNINMEM:
  176. case ICC_THISCALL_OBJLAST_RETURNINMEM:
  177. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer);
  178. break;
  179. case ICC_VIRTUAL_THISCALL:
  180. case ICC_VIRTUAL_THISCALL_OBJFIRST:
  181. case ICC_VIRTUAL_THISCALL_OBJLAST:
  182. {
  183. // Get virtual function table from the object pointer
  184. asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
  185. retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]);
  186. }
  187. break;
  188. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  189. case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
  190. case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
  191. {
  192. // Get virtual function table from the object pointer
  193. asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
  194. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], retPointer);
  195. }
  196. break;
  197. case ICC_CDECL_OBJLAST:
  198. retQW = CallCDeclFunctionObjLast(obj, args, paramSize<<2, func);
  199. break;
  200. case ICC_CDECL_OBJLAST_RETURNINMEM:
  201. // Call the system object method as a cdecl with the obj ref as the last parameter
  202. retQW = CallCDeclFunctionRetByRefObjLast(obj, args, paramSize<<2, func, retPointer);
  203. break;
  204. case ICC_CDECL_OBJFIRST:
  205. // Call the system object method as a cdecl with the obj ref as the first parameter
  206. retQW = CallCDeclFunctionObjFirst(obj, args, paramSize<<2, func);
  207. break;
  208. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  209. // Call the system object method as a cdecl with the obj ref as the first parameter
  210. retQW = CallCDeclFunctionRetByRefObjFirst(obj, args, paramSize<<2, func, retPointer);
  211. break;
  212. default:
  213. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  214. }
  215. // If the return is a float value we need to get the value from the FP register
  216. if( sysFunc->hostReturnFloat )
  217. {
  218. if( sysFunc->hostReturnSize == 1 )
  219. *(asDWORD*)&retQW = GetReturnedFloat();
  220. else
  221. retQW = GetReturnedDouble();
  222. }
  223. return retQW;
  224. }
  225. // On GCC we need to prevent the compiler from inlining these assembler routines when
  226. // optimizing for speed (-O3), as the loop labels get duplicated which cause compile errors.
  227. #ifdef __GNUC__
  228. #define NOINLINE __attribute ((__noinline__))
  229. #else
  230. #define NOINLINE
  231. #endif
  232. asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
  233. {
  234. volatile asQWORD retQW = 0;
  235. #if defined ASM_INTEL
  236. // Copy the data to the real stack. If we fail to do
  237. // this we may run into trouble in case of exceptions.
  238. __asm
  239. {
  240. // We must save registers that are used
  241. push ecx
  242. // Clear the FPU stack, in case the called function doesn't do it by itself
  243. CLEAR_FPU_STACK
  244. // Copy arguments from script
  245. // stack to application stack
  246. mov ecx, paramSize
  247. mov eax, args
  248. add eax, ecx
  249. cmp ecx, 0
  250. je endcopy
  251. copyloop:
  252. sub eax, 4
  253. push dword ptr [eax]
  254. sub ecx, 4
  255. jne copyloop
  256. endcopy:
  257. // Call function
  258. call [func]
  259. // Pop arguments from stack
  260. add esp, paramSize
  261. // Copy return value from EAX:EDX
  262. lea ecx, retQW
  263. mov [ecx], eax
  264. mov 4[ecx], edx
  265. // Restore registers
  266. pop ecx
  267. }
  268. #elif defined ASM_AT_N_T
  269. // It is not possible to rely on ESP or BSP to refer to variables or arguments on the stack
  270. // depending on compiler settings BSP may not even be used, and the ESP is not always on the
  271. // same offset from the local variables. Because the code adjusts the ESP register it is not
  272. // possible to inform the arguments through symbolic names below.
  273. // It's not also not possible to rely on the memory layout of the function arguments, because
  274. // on some compiler versions and settings the arguments may be copied to local variables with a
  275. // different ordering before they are accessed by the rest of the code.
  276. // I'm copying the arguments into this array where I know the exact memory layout. The address
  277. // of this array will then be passed to the inline asm in the EDX register.
  278. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  279. asm __volatile__(
  280. #ifdef __OPTIMIZE__
  281. // When compiled with optimizations the stack unwind doesn't work properly,
  282. // causing exceptions to crash the application. By adding this prologue
  283. // and the epilogue below, the stack unwind works as it should.
  284. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  285. "pushl %%ebp \n"
  286. ".cfi_adjust_cfa_offset 4 \n"
  287. ".cfi_rel_offset ebp, 0 \n"
  288. "movl %%esp, %%ebp \n"
  289. ".cfi_def_cfa_register ebp \n"
  290. #endif
  291. _S(CLEAR_FPU_STACK) "\n"
  292. "pushl %%ebx \n"
  293. "movl %%edx, %%ebx \n"
  294. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  295. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  296. // to calculate how much we will put on the stack during this call.
  297. "movl 4(%%ebx), %%eax \n" // paramSize
  298. "addl $4, %%eax \n" // counting esp that we will push on the stack
  299. "movl %%esp, %%ecx \n"
  300. "subl %%eax, %%ecx \n"
  301. "andl $15, %%ecx \n"
  302. "movl %%esp, %%eax \n"
  303. "subl %%ecx, %%esp \n"
  304. "pushl %%eax \n" // Store the original stack pointer
  305. // Copy all arguments to the stack and call the function
  306. "movl 4(%%ebx), %%ecx \n" // paramSize
  307. "movl 0(%%ebx), %%eax \n" // args
  308. "addl %%ecx, %%eax \n" // push arguments on the stack
  309. "cmp $0, %%ecx \n"
  310. "je endcopy \n"
  311. "copyloop: \n"
  312. "subl $4, %%eax \n"
  313. "pushl (%%eax) \n"
  314. "subl $4, %%ecx \n"
  315. "jne copyloop \n"
  316. "endcopy: \n"
  317. "call *8(%%ebx) \n"
  318. "addl 4(%%ebx), %%esp \n" // pop arguments
  319. // Pop the alignment bytes
  320. "popl %%esp \n"
  321. "popl %%ebx \n"
  322. #ifdef __OPTIMIZE__
  323. // Epilogue
  324. "movl %%ebp, %%esp \n"
  325. ".cfi_def_cfa_register esp \n"
  326. "popl %%ebp \n"
  327. ".cfi_adjust_cfa_offset -4 \n"
  328. ".cfi_restore ebp \n"
  329. #endif
  330. // Copy EAX:EDX to retQW. As the stack pointer has been
  331. // restored it is now safe to access the local variable
  332. "leal %1, %%ecx \n"
  333. "movl %%eax, 0(%%ecx) \n"
  334. "movl %%edx, 4(%%ecx) \n"
  335. : // output
  336. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  337. : "%eax", "%ecx" // clobber
  338. );
  339. #endif
  340. return retQW;
  341. }
  342. asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  343. {
  344. volatile asQWORD retQW = 0;
  345. #if defined ASM_INTEL
  346. // Copy the data to the real stack. If we fail to do
  347. // this we may run into trouble in case of exceptions.
  348. __asm
  349. {
  350. // We must save registers that are used
  351. push ecx
  352. // Clear the FPU stack, in case the called function doesn't do it by itself
  353. CLEAR_FPU_STACK
  354. // Push the object pointer as the last argument to the function
  355. push obj
  356. // Copy arguments from script
  357. // stack to application stack
  358. mov ecx, paramSize
  359. mov eax, args
  360. add eax, ecx
  361. cmp ecx, 0
  362. je endcopy
  363. copyloop:
  364. sub eax, 4
  365. push dword ptr [eax]
  366. sub ecx, 4
  367. jne copyloop
  368. endcopy:
  369. // Call function
  370. call [func]
  371. // Pop arguments from stack
  372. add esp, paramSize
  373. add esp, 4
  374. // Copy return value from EAX:EDX
  375. lea ecx, retQW
  376. mov [ecx], eax
  377. mov 4[ecx], edx
  378. // Restore registers
  379. pop ecx
  380. }
  381. #elif defined ASM_AT_N_T
  382. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  383. asm __volatile__ (
  384. #ifdef __OPTIMIZE__
  385. // When compiled with optimizations the stack unwind doesn't work properly,
  386. // causing exceptions to crash the application. By adding this prologue
  387. // and the epilogue below, the stack unwind works as it should.
  388. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  389. "pushl %%ebp \n"
  390. ".cfi_adjust_cfa_offset 4 \n"
  391. ".cfi_rel_offset ebp, 0 \n"
  392. "movl %%esp, %%ebp \n"
  393. ".cfi_def_cfa_register ebp \n"
  394. #endif
  395. _S(CLEAR_FPU_STACK) "\n"
  396. "pushl %%ebx \n"
  397. "movl %%edx, %%ebx \n"
  398. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  399. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  400. // to calculate how much we will put on the stack during this call.
  401. "movl 8(%%ebx), %%eax \n" // paramSize
  402. "addl $8, %%eax \n" // counting esp that we will push on the stack
  403. "movl %%esp, %%ecx \n"
  404. "subl %%eax, %%ecx \n"
  405. "andl $15, %%ecx \n"
  406. "movl %%esp, %%eax \n"
  407. "subl %%ecx, %%esp \n"
  408. "pushl %%eax \n" // Store the original stack pointer
  409. "pushl 0(%%ebx) \n" // obj
  410. "movl 8(%%ebx), %%ecx \n" // paramSize
  411. "movl 4(%%ebx), %%eax \n" // args
  412. "addl %%ecx, %%eax \n" // push arguments on the stack
  413. "cmp $0, %%ecx \n"
  414. "je endcopy8 \n"
  415. "copyloop8: \n"
  416. "subl $4, %%eax \n"
  417. "pushl (%%eax) \n"
  418. "subl $4, %%ecx \n"
  419. "jne copyloop8 \n"
  420. "endcopy8: \n"
  421. "call *12(%%ebx) \n"
  422. "addl 8(%%ebx), %%esp \n" // pop arguments
  423. "addl $4, %%esp \n" // pop obj
  424. // Pop the alignment bytes
  425. "popl %%esp \n"
  426. "popl %%ebx \n"
  427. #ifdef __OPTIMIZE__
  428. // Epilogue
  429. "movl %%ebp, %%esp \n"
  430. ".cfi_def_cfa_register esp \n"
  431. "popl %%ebp \n"
  432. ".cfi_adjust_cfa_offset -4 \n"
  433. ".cfi_restore ebp \n"
  434. #endif
  435. // Copy EAX:EDX to retQW. As the stack pointer has been
  436. // restored it is now safe to access the local variable
  437. "leal %1, %%ecx \n"
  438. "movl %%eax, 0(%%ecx) \n"
  439. "movl %%edx, 4(%%ecx) \n"
  440. : // output
  441. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  442. : "%eax", "%ecx" // clobber
  443. );
  444. #endif
  445. return retQW;
  446. }
  447. asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  448. {
  449. volatile asQWORD retQW = 0;
  450. #if defined ASM_INTEL
  451. // Copy the data to the real stack. If we fail to do
  452. // this we may run into trouble in case of exceptions.
  453. __asm
  454. {
  455. // We must save registers that are used
  456. push ecx
  457. // Clear the FPU stack, in case the called function doesn't do it by itself
  458. CLEAR_FPU_STACK
  459. // Copy arguments from script
  460. // stack to application stack
  461. mov ecx, paramSize
  462. mov eax, args
  463. add eax, ecx
  464. cmp ecx, 0
  465. je endcopy
  466. copyloop:
  467. sub eax, 4
  468. push dword ptr [eax]
  469. sub ecx, 4
  470. jne copyloop
  471. endcopy:
  472. // push object as first parameter
  473. push obj
  474. // Call function
  475. call [func]
  476. // Pop arguments from stack
  477. add esp, paramSize
  478. add esp, 4
  479. // Copy return value from EAX:EDX
  480. lea ecx, retQW
  481. mov [ecx], eax
  482. mov 4[ecx], edx
  483. // Restore registers
  484. pop ecx
  485. }
  486. #elif defined ASM_AT_N_T
  487. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  488. asm __volatile__ (
  489. #ifdef __OPTIMIZE__
  490. // When compiled with optimizations the stack unwind doesn't work properly,
  491. // causing exceptions to crash the application. By adding this prologue
  492. // and the epilogue below, the stack unwind works as it should.
  493. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  494. "pushl %%ebp \n"
  495. ".cfi_adjust_cfa_offset 4 \n"
  496. ".cfi_rel_offset ebp, 0 \n"
  497. "movl %%esp, %%ebp \n"
  498. ".cfi_def_cfa_register ebp \n"
  499. #endif
  500. _S(CLEAR_FPU_STACK) "\n"
  501. "pushl %%ebx \n"
  502. "movl %%edx, %%ebx \n"
  503. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  504. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  505. // to calculate how much we will put on the stack during this call.
  506. "movl 8(%%ebx), %%eax \n" // paramSize
  507. "addl $8, %%eax \n" // counting esp that we will push on the stack
  508. "movl %%esp, %%ecx \n"
  509. "subl %%eax, %%ecx \n"
  510. "andl $15, %%ecx \n"
  511. "movl %%esp, %%eax \n"
  512. "subl %%ecx, %%esp \n"
  513. "pushl %%eax \n" // Store the original stack pointer
  514. "movl 8(%%ebx), %%ecx \n" // paramSize
  515. "movl 4(%%ebx), %%eax \n" // args
  516. "addl %%ecx, %%eax \n" // push arguments on the stack
  517. "cmp $0, %%ecx \n"
  518. "je endcopy6 \n"
  519. "copyloop6: \n"
  520. "subl $4, %%eax \n"
  521. "pushl (%%eax) \n"
  522. "subl $4, %%ecx \n"
  523. "jne copyloop6 \n"
  524. "endcopy6: \n"
  525. "pushl 0(%%ebx) \n" // push obj
  526. "call *12(%%ebx) \n"
  527. "addl 8(%%ebx), %%esp \n" // pop arguments
  528. "addl $4, %%esp \n" // pop obj
  529. // Pop the alignment bytes
  530. "popl %%esp \n"
  531. "popl %%ebx \n"
  532. #ifdef __OPTIMIZE__
  533. // Epilogue
  534. "movl %%ebp, %%esp \n"
  535. ".cfi_def_cfa_register esp \n"
  536. "popl %%ebp \n"
  537. ".cfi_adjust_cfa_offset -4 \n"
  538. ".cfi_restore ebp \n"
  539. #endif
  540. // Copy EAX:EDX to retQW. As the stack pointer has been
  541. // restored it is now safe to access the local variable
  542. "leal %1, %%ecx \n"
  543. "movl %%eax, 0(%%ecx) \n"
  544. "movl %%edx, 4(%%ecx) \n"
  545. : // output
  546. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  547. : "%eax", "%ecx" // clobber
  548. );
  549. #endif
  550. return retQW;
  551. }
  552. asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  553. {
  554. volatile asQWORD retQW = 0;
  555. #if defined ASM_INTEL
  556. // Copy the data to the real stack. If we fail to do
  557. // this we may run into trouble in case of exceptions.
  558. __asm
  559. {
  560. // We must save registers that are used
  561. push ecx
  562. // Clear the FPU stack, in case the called function doesn't do it by itself
  563. CLEAR_FPU_STACK
  564. // Copy arguments from script
  565. // stack to application stack
  566. mov ecx, paramSize
  567. mov eax, args
  568. add eax, ecx
  569. cmp ecx, 0
  570. je endcopy
  571. copyloop:
  572. sub eax, 4
  573. push dword ptr [eax]
  574. sub ecx, 4
  575. jne copyloop
  576. endcopy:
  577. // Push the object pointer
  578. push obj
  579. // Push the return pointer
  580. push retPtr;
  581. // Call function
  582. call [func]
  583. // Pop arguments from stack
  584. add esp, paramSize
  585. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  586. // Pop the return pointer
  587. add esp, 8
  588. #else
  589. add esp, 4
  590. #endif
  591. // Copy return value from EAX:EDX
  592. lea ecx, retQW
  593. mov [ecx], eax
  594. mov 4[ecx], edx
  595. // Restore registers
  596. pop ecx
  597. }
  598. #elif defined ASM_AT_N_T
  599. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  600. asm __volatile__ (
  601. #ifdef __OPTIMIZE__
  602. // When compiled with optimizations the stack unwind doesn't work properly,
  603. // causing exceptions to crash the application. By adding this prologue
  604. // and the epilogue below, the stack unwind works as it should.
  605. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  606. "pushl %%ebp \n"
  607. ".cfi_adjust_cfa_offset 4 \n"
  608. ".cfi_rel_offset ebp, 0 \n"
  609. "movl %%esp, %%ebp \n"
  610. ".cfi_def_cfa_register ebp \n"
  611. #endif
  612. _S(CLEAR_FPU_STACK) "\n"
  613. "pushl %%ebx \n"
  614. "movl %%edx, %%ebx \n"
  615. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  616. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  617. // to calculate how much we will put on the stack during this call.
  618. "movl 8(%%ebx), %%eax \n" // paramSize
  619. "addl $12, %%eax \n" // counting esp that we will push on the stack
  620. "movl %%esp, %%ecx \n"
  621. "subl %%eax, %%ecx \n"
  622. "andl $15, %%ecx \n"
  623. "movl %%esp, %%eax \n"
  624. "subl %%ecx, %%esp \n"
  625. "pushl %%eax \n" // Store the original stack pointer
  626. "movl 8(%%ebx), %%ecx \n" // paramSize
  627. "movl 4(%%ebx), %%eax \n" // args
  628. "addl %%ecx, %%eax \n" // push arguments on the stack
  629. "cmp $0, %%ecx \n"
  630. "je endcopy5 \n"
  631. "copyloop5: \n"
  632. "subl $4, %%eax \n"
  633. "pushl (%%eax) \n"
  634. "subl $4, %%ecx \n"
  635. "jne copyloop5 \n"
  636. "endcopy5: \n"
  637. "pushl 0(%%ebx) \n" // push object first
  638. "pushl 16(%%ebx) \n" // retPtr
  639. "call *12(%%ebx) \n" // func
  640. "addl 8(%%ebx), %%esp \n" // pop arguments
  641. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  642. "addl $8, %%esp \n" // Pop the return pointer and object pointer
  643. #else
  644. "addl $4, %%esp \n" // Pop the object pointer
  645. #endif
  646. // Pop the alignment bytes
  647. "popl %%esp \n"
  648. "popl %%ebx \n"
  649. #ifdef __OPTIMIZE__
  650. // Epilogue
  651. "movl %%ebp, %%esp \n"
  652. ".cfi_def_cfa_register esp \n"
  653. "popl %%ebp \n"
  654. ".cfi_adjust_cfa_offset -4 \n"
  655. ".cfi_restore ebp \n"
  656. #endif
  657. // Copy EAX:EDX to retQW. As the stack pointer has been
  658. // restored it is now safe to access the local variable
  659. "leal %1, %%ecx \n"
  660. "movl %%eax, 0(%%ecx) \n"
  661. "movl %%edx, 4(%%ecx) \n"
  662. : // output
  663. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  664. : "%eax", "%ecx" // clobber
  665. );
  666. #endif
  667. return retQW;
  668. }
  669. asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  670. {
  671. volatile asQWORD retQW = 0;
  672. #if defined ASM_INTEL
  673. // Copy the data to the real stack. If we fail to do
  674. // this we may run into trouble in case of exceptions.
  675. __asm
  676. {
  677. // We must save registers that are used
  678. push ecx
  679. // Clear the FPU stack, in case the called function doesn't do it by itself
  680. CLEAR_FPU_STACK
  681. // Copy arguments from script
  682. // stack to application stack
  683. mov ecx, paramSize
  684. mov eax, args
  685. add eax, ecx
  686. cmp ecx, 0
  687. je endcopy
  688. copyloop:
  689. sub eax, 4
  690. push dword ptr [eax]
  691. sub ecx, 4
  692. jne copyloop
  693. endcopy:
  694. // Push the return pointer
  695. push retPtr;
  696. // Call function
  697. call [func]
  698. // Pop arguments from stack
  699. add esp, paramSize
  700. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  701. // Pop the return pointer
  702. add esp, 4
  703. #endif
  704. // Copy return value from EAX:EDX
  705. lea ecx, retQW
  706. mov [ecx], eax
  707. mov 4[ecx], edx
  708. // Restore registers
  709. pop ecx
  710. // return value in EAX or EAX:EDX
  711. }
  712. #elif defined ASM_AT_N_T
  713. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  714. asm __volatile__ (
  715. #ifdef __OPTIMIZE__
  716. // When compiled with optimizations the stack unwind doesn't work properly,
  717. // causing exceptions to crash the application. By adding this prologue
  718. // and the epilogue below, the stack unwind works as it should.
  719. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  720. "pushl %%ebp \n"
  721. ".cfi_adjust_cfa_offset 4 \n"
  722. ".cfi_rel_offset ebp, 0 \n"
  723. "movl %%esp, %%ebp \n"
  724. ".cfi_def_cfa_register ebp \n"
  725. #endif
  726. _S(CLEAR_FPU_STACK) "\n"
  727. "pushl %%ebx \n"
  728. "movl %%edx, %%ebx \n"
  729. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  730. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  731. // to calculate how much we will put on the stack during this call.
  732. "movl 4(%%ebx), %%eax \n" // paramSize
  733. "addl $8, %%eax \n" // counting esp that we will push on the stack
  734. "movl %%esp, %%ecx \n"
  735. "subl %%eax, %%ecx \n"
  736. "andl $15, %%ecx \n"
  737. "movl %%esp, %%eax \n"
  738. "subl %%ecx, %%esp \n"
  739. "pushl %%eax \n" // Store the original stack pointer
  740. "movl 4(%%ebx), %%ecx \n" // paramSize
  741. "movl 0(%%ebx), %%eax \n" // args
  742. "addl %%ecx, %%eax \n" // push arguments on the stack
  743. "cmp $0, %%ecx \n"
  744. "je endcopy7 \n"
  745. "copyloop7: \n"
  746. "subl $4, %%eax \n"
  747. "pushl (%%eax) \n"
  748. "subl $4, %%ecx \n"
  749. "jne copyloop7 \n"
  750. "endcopy7: \n"
  751. "pushl 12(%%ebx) \n" // retPtr
  752. "call *8(%%ebx) \n" // func
  753. "addl 4(%%ebx), %%esp \n" // pop arguments
  754. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  755. "addl $4, %%esp \n" // Pop the return pointer
  756. #endif
  757. // Pop the alignment bytes
  758. "popl %%esp \n"
  759. "popl %%ebx \n"
  760. #ifdef __OPTIMIZE__
  761. // Epilogue
  762. "movl %%ebp, %%esp \n"
  763. ".cfi_def_cfa_register esp \n"
  764. "popl %%ebp \n"
  765. ".cfi_adjust_cfa_offset -4 \n"
  766. ".cfi_restore ebp \n"
  767. #endif
  768. // Copy EAX:EDX to retQW. As the stack pointer has been
  769. // restored it is now safe to access the local variable
  770. "leal %1, %%ecx \n"
  771. "movl %%eax, 0(%%ecx) \n"
  772. "movl %%edx, 4(%%ecx) \n"
  773. : // output
  774. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  775. : "%eax", "%ecx" // clobber
  776. );
  777. #endif
  778. return retQW;
  779. }
  780. asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  781. {
  782. volatile asQWORD retQW = 0;
  783. #if defined ASM_INTEL
  784. // Copy the data to the real stack. If we fail to do
  785. // this we may run into trouble in case of exceptions.
  786. __asm
  787. {
  788. // We must save registers that are used
  789. push ecx
  790. // Clear the FPU stack, in case the called function doesn't do it by itself
  791. CLEAR_FPU_STACK
  792. push obj
  793. // Copy arguments from script
  794. // stack to application stack
  795. mov ecx, paramSize
  796. mov eax, args
  797. add eax, ecx
  798. cmp ecx, 0
  799. je endcopy
  800. copyloop:
  801. sub eax, 4
  802. push dword ptr [eax]
  803. sub ecx, 4
  804. jne copyloop
  805. endcopy:
  806. // Push the return pointer
  807. push retPtr;
  808. // Call function
  809. call [func]
  810. // Pop arguments from stack
  811. add esp, paramSize
  812. add esp, 4
  813. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  814. // Pop the return pointer
  815. add esp, 4
  816. #endif
  817. // Copy return value from EAX:EDX
  818. lea ecx, retQW
  819. mov [ecx], eax
  820. mov 4[ecx], edx
  821. // Restore registers
  822. pop ecx
  823. }
  824. #elif defined ASM_AT_N_T
  825. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  826. asm __volatile__ (
  827. #ifdef __OPTIMIZE__
  828. // When compiled with optimizations the stack unwind doesn't work properly,
  829. // causing exceptions to crash the application. By adding this prologue
  830. // and the epilogue below, the stack unwind works as it should.
  831. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  832. "pushl %%ebp \n"
  833. ".cfi_adjust_cfa_offset 4 \n"
  834. ".cfi_rel_offset ebp, 0 \n"
  835. "movl %%esp, %%ebp \n"
  836. ".cfi_def_cfa_register ebp \n"
  837. #endif
  838. _S(CLEAR_FPU_STACK) "\n"
  839. "pushl %%ebx \n"
  840. "movl %%edx, %%ebx \n"
  841. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  842. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  843. // to calculate how much we will put on the stack during this call.
  844. "movl 8(%%ebx), %%eax \n" // paramSize
  845. "addl $12, %%eax \n" // counting esp that we will push on the stack
  846. "movl %%esp, %%ecx \n"
  847. "subl %%eax, %%ecx \n"
  848. "andl $15, %%ecx \n"
  849. "movl %%esp, %%eax \n"
  850. "subl %%ecx, %%esp \n"
  851. "pushl %%eax \n" // Store the original stack pointer
  852. "pushl 0(%%ebx) \n" // obj
  853. "movl 8(%%ebx), %%ecx \n" // paramSize
  854. "movl 4(%%ebx), %%eax \n" // args
  855. "addl %%ecx, %%eax \n" // push arguments on the stack
  856. "cmp $0, %%ecx \n"
  857. "je endcopy4 \n"
  858. "copyloop4: \n"
  859. "subl $4, %%eax \n"
  860. "pushl (%%eax) \n"
  861. "subl $4, %%ecx \n"
  862. "jne copyloop4 \n"
  863. "endcopy4: \n"
  864. "pushl 16(%%ebx) \n" // retPtr
  865. "call *12(%%ebx) \n" // func
  866. "addl 8(%%ebx), %%esp \n" // pop arguments
  867. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  868. "addl $8, %%esp \n" // Pop the return pointer and object pointer
  869. #else
  870. "addl $4, %%esp \n" // Pop the object pointer
  871. #endif
  872. // Pop the alignment bytes
  873. "popl %%esp \n"
  874. "popl %%ebx \n"
  875. #ifdef __OPTIMIZE__
  876. // Epilogue
  877. "movl %%ebp, %%esp \n"
  878. ".cfi_def_cfa_register esp \n"
  879. "popl %%ebp \n"
  880. ".cfi_adjust_cfa_offset -4 \n"
  881. ".cfi_restore ebp \n"
  882. #endif
  883. // Copy EAX:EDX to retQW. As the stack pointer has been
  884. // restored it is now safe to access the local variable
  885. "leal %1, %%ecx \n"
  886. "movl %%eax, 0(%%ecx) \n"
  887. "movl %%edx, 4(%%ecx) \n"
  888. : // output
  889. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  890. : "%eax", "%ecx" // clobber
  891. );
  892. #endif
  893. return retQW;
  894. }
  895. asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
  896. {
  897. volatile asQWORD retQW = 0;
  898. #if defined ASM_INTEL
  899. // Copy the data to the real stack. If we fail to do
  900. // this we may run into trouble in case of exceptions.
  901. __asm
  902. {
  903. // We must save registers that are used
  904. push ecx
  905. // Clear the FPU stack, in case the called function doesn't do it by itself
  906. CLEAR_FPU_STACK
  907. // Copy arguments from script
  908. // stack to application stack
  909. mov ecx, paramSize
  910. mov eax, args
  911. add eax, ecx
  912. cmp ecx, 0
  913. je endcopy
  914. copyloop:
  915. sub eax, 4
  916. push dword ptr [eax]
  917. sub ecx, 4
  918. jne copyloop
  919. endcopy:
  920. // Call function
  921. call [func]
  922. // The callee already removed parameters from the stack
  923. // Copy return value from EAX:EDX
  924. lea ecx, retQW
  925. mov [ecx], eax
  926. mov 4[ecx], edx
  927. // Restore registers
  928. pop ecx
  929. }
  930. #elif defined ASM_AT_N_T
  931. volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  932. asm __volatile__ (
  933. #ifdef __OPTIMIZE__
  934. // When compiled with optimizations the stack unwind doesn't work properly,
  935. // causing exceptions to crash the application. By adding this prologue
  936. // and the epilogue below, the stack unwind works as it should.
  937. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  938. "pushl %%ebp \n"
  939. ".cfi_adjust_cfa_offset 4 \n"
  940. ".cfi_rel_offset ebp, 0 \n"
  941. "movl %%esp, %%ebp \n"
  942. ".cfi_def_cfa_register ebp \n"
  943. #endif
  944. _S(CLEAR_FPU_STACK) "\n"
  945. "pushl %%ebx \n"
  946. "movl %%edx, %%ebx \n"
  947. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  948. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  949. // to calculate how much we will put on the stack during this call.
  950. "movl 4(%%ebx), %%eax \n" // paramSize
  951. "addl $4, %%eax \n" // counting esp that we will push on the stack
  952. "movl %%esp, %%ecx \n"
  953. "subl %%eax, %%ecx \n"
  954. "andl $15, %%ecx \n"
  955. "movl %%esp, %%eax \n"
  956. "subl %%ecx, %%esp \n"
  957. "pushl %%eax \n" // Store the original stack pointer
  958. "movl 4(%%ebx), %%ecx \n" // paramSize
  959. "movl 0(%%ebx), %%eax \n" // args
  960. "addl %%ecx, %%eax \n" // push arguments on the stack
  961. "cmp $0, %%ecx \n"
  962. "je endcopy2 \n"
  963. "copyloop2: \n"
  964. "subl $4, %%eax \n"
  965. "pushl (%%eax) \n"
  966. "subl $4, %%ecx \n"
  967. "jne copyloop2 \n"
  968. "endcopy2: \n"
  969. "call *8(%%ebx) \n" // callee pops the arguments
  970. // Pop the alignment bytes
  971. "popl %%esp \n"
  972. "popl %%ebx \n"
  973. #ifdef __OPTIMIZE__
  974. // Epilogue
  975. "movl %%ebp, %%esp \n"
  976. ".cfi_def_cfa_register esp \n"
  977. "popl %%ebp \n"
  978. ".cfi_adjust_cfa_offset -4 \n"
  979. ".cfi_restore ebp \n"
  980. #endif
  981. // Copy EAX:EDX to retQW. As the stack pointer has been
  982. // restored it is now safe to access the local variable
  983. "leal %1, %%ecx \n"
  984. "movl %%eax, 0(%%ecx) \n"
  985. "movl %%edx, 4(%%ecx) \n"
  986. : // output
  987. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  988. : "%eax", "%ecx" // clobber
  989. );
  990. #endif
  991. return retQW;
  992. }
  993. asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
  994. {
  995. volatile asQWORD retQW = 0;
  996. #if defined ASM_INTEL
  997. // Copy the data to the real stack. If we fail to do
  998. // this we may run into trouble in case of exceptions.
  999. __asm
  1000. {
  1001. // We must save registers that are used
  1002. push ecx
  1003. // Clear the FPU stack, in case the called function doesn't do it by itself
  1004. CLEAR_FPU_STACK
  1005. // Copy arguments from script
  1006. // stack to application stack
  1007. mov ecx, paramSize
  1008. mov eax, args
  1009. add eax, ecx
  1010. cmp ecx, 0
  1011. je endcopy
  1012. copyloop:
  1013. sub eax, 4
  1014. push dword ptr [eax]
  1015. sub ecx, 4
  1016. jne copyloop
  1017. endcopy:
  1018. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1019. // Push the object pointer on the stack
  1020. push obj
  1021. #else
  1022. // Move object pointer to ECX
  1023. mov ecx, obj
  1024. #endif
  1025. // Call function
  1026. call [func]
  1027. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  1028. // Pop arguments
  1029. add esp, paramSize
  1030. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1031. // Pop object pointer
  1032. add esp, 4
  1033. #endif
  1034. #endif
  1035. // Copy return value from EAX:EDX
  1036. lea ecx, retQW
  1037. mov [ecx], eax
  1038. mov 4[ecx], edx
  1039. // Restore registers
  1040. pop ecx
  1041. }
  1042. #elif defined ASM_AT_N_T
  1043. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
  1044. asm __volatile__ (
  1045. #ifdef __OPTIMIZE__
  1046. // When compiled with optimizations the stack unwind doesn't work properly,
  1047. // causing exceptions to crash the application. By adding this prologue
  1048. // and the epilogue below, the stack unwind works as it should.
  1049. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  1050. "pushl %%ebp \n"
  1051. ".cfi_adjust_cfa_offset 4 \n"
  1052. ".cfi_rel_offset ebp, 0 \n"
  1053. "movl %%esp, %%ebp \n"
  1054. ".cfi_def_cfa_register ebp \n"
  1055. #endif
  1056. _S(CLEAR_FPU_STACK) "\n"
  1057. "pushl %%ebx \n"
  1058. "movl %%edx, %%ebx \n"
  1059. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  1060. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  1061. // to calculate how much we will put on the stack during this call.
  1062. "movl 8(%%ebx), %%eax \n" // paramSize
  1063. "addl $8, %%eax \n" // counting esp that we will push on the stack
  1064. "movl %%esp, %%ecx \n"
  1065. "subl %%eax, %%ecx \n"
  1066. "andl $15, %%ecx \n"
  1067. "movl %%esp, %%eax \n"
  1068. "subl %%ecx, %%esp \n"
  1069. "pushl %%eax \n" // Store the original stack pointer
  1070. "movl 8(%%ebx), %%ecx \n" // paramSize
  1071. "movl 4(%%ebx), %%eax \n" // args
  1072. "addl %%ecx, %%eax \n" // push all arguments on the stack
  1073. "cmp $0, %%ecx \n"
  1074. "je endcopy1 \n"
  1075. "copyloop1: \n"
  1076. "subl $4, %%eax \n"
  1077. "pushl (%%eax) \n"
  1078. "subl $4, %%ecx \n"
  1079. "jne copyloop1 \n"
  1080. "endcopy1: \n"
  1081. "movl 0(%%ebx), %%ecx \n" // move obj into ECX
  1082. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1083. "pushl %%ecx \n" // push obj on the stack
  1084. #endif
  1085. "call *12(%%ebx) \n"
  1086. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  1087. "addl 8(%%ebx), %%esp \n" // pop arguments
  1088. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1089. "addl $4, %%esp \n" // pop obj
  1090. #endif
  1091. #endif
  1092. // Pop the alignment bytes
  1093. "popl %%esp \n"
  1094. "popl %%ebx \n"
  1095. #ifdef __OPTIMIZE__
  1096. // Epilogue
  1097. "movl %%ebp, %%esp \n"
  1098. ".cfi_def_cfa_register esp \n"
  1099. "popl %%ebp \n"
  1100. ".cfi_adjust_cfa_offset -4 \n"
  1101. ".cfi_restore ebp \n"
  1102. #endif
  1103. // Copy EAX:EDX to retQW. As the stack pointer has been
  1104. // restored it is now safe to access the local variable
  1105. "leal %1, %%ecx \n"
  1106. "movl %%eax, 0(%%ecx) \n"
  1107. "movl %%edx, 4(%%ecx) \n"
  1108. : // output
  1109. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  1110. : "%eax", "%ecx" // clobber
  1111. );
  1112. #endif
  1113. return retQW;
  1114. }
  1115. asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
  1116. {
  1117. volatile asQWORD retQW = 0;
  1118. #if defined ASM_INTEL
  1119. // Copy the data to the real stack. If we fail to do
  1120. // this we may run into trouble in case of exceptions.
  1121. __asm
  1122. {
  1123. // We must save registers that are used
  1124. push ecx
  1125. // Clear the FPU stack, in case the called function doesn't do it by itself
  1126. CLEAR_FPU_STACK
  1127. // Copy arguments from script
  1128. // stack to application stack
  1129. mov ecx, paramSize
  1130. mov eax, args
  1131. add eax, ecx
  1132. cmp ecx, 0
  1133. je endcopy
  1134. copyloop:
  1135. sub eax, 4
  1136. push dword ptr [eax]
  1137. sub ecx, 4
  1138. jne copyloop
  1139. endcopy:
  1140. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1141. // Push the object pointer on the stack
  1142. push obj
  1143. #else
  1144. // Move object pointer to ECX
  1145. mov ecx, obj
  1146. #endif
  1147. // Push the return pointer
  1148. push retPtr
  1149. // Call function
  1150. call [func]
  1151. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  1152. // Pop the return pointer
  1153. add esp, 4
  1154. #endif
  1155. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  1156. // Pop arguments
  1157. add esp, paramSize
  1158. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1159. // Pop object pointer
  1160. add esp, 4
  1161. #endif
  1162. #endif
  1163. // Copy return value from EAX:EDX
  1164. lea ecx, retQW
  1165. mov [ecx], eax
  1166. mov 4[ecx], edx
  1167. // Restore registers
  1168. pop ecx
  1169. }
  1170. #elif defined ASM_AT_N_T
  1171. volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
  1172. asm __volatile__ (
  1173. #ifdef __OPTIMIZE__
  1174. // When compiled with optimizations the stack unwind doesn't work properly,
  1175. // causing exceptions to crash the application. By adding this prologue
  1176. // and the epilogue below, the stack unwind works as it should.
  1177. // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below
  1178. "pushl %%ebp \n"
  1179. ".cfi_adjust_cfa_offset 4 \n"
  1180. ".cfi_rel_offset ebp, 0 \n"
  1181. "movl %%esp, %%ebp \n"
  1182. ".cfi_def_cfa_register ebp \n"
  1183. #endif
  1184. _S(CLEAR_FPU_STACK) "\n"
  1185. "pushl %%ebx \n"
  1186. "movl %%edx, %%ebx \n"
  1187. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  1188. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  1189. // to calculate how much we will put on the stack during this call.
  1190. "movl 8(%%ebx), %%eax \n" // paramSize
  1191. "addl $12, %%eax \n" // counting esp that we will push on the stack
  1192. "movl %%esp, %%ecx \n"
  1193. "subl %%eax, %%ecx \n"
  1194. "andl $15, %%ecx \n"
  1195. "movl %%esp, %%eax \n"
  1196. "subl %%ecx, %%esp \n"
  1197. "pushl %%eax \n" // Store the original stack pointer
  1198. "movl 8(%%ebx), %%ecx \n" // paramSize
  1199. "movl 4(%%ebx), %%eax \n" // args
  1200. "addl %%ecx, %%eax \n" // push all arguments to the stack
  1201. "cmp $0, %%ecx \n"
  1202. "je endcopy3 \n"
  1203. "copyloop3: \n"
  1204. "subl $4, %%eax \n"
  1205. "pushl (%%eax) \n"
  1206. "subl $4, %%ecx \n"
  1207. "jne copyloop3 \n"
  1208. "endcopy3: \n"
  1209. #ifdef AS_MINGW47
  1210. // MinGW made some strange choices with 4.7 and the thiscall calling convention,
  1211. // returning an object in memory is completely different from when not returning
  1212. // in memory
  1213. "pushl 0(%%ebx) \n" // push obj on the stack
  1214. "movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX
  1215. "call *12(%%ebx) \n" // call the function
  1216. #else
  1217. "movl 0(%%ebx), %%ecx \n" // move obj into ECX
  1218. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1219. "pushl %%ecx \n" // push obj on the stack
  1220. #endif
  1221. "pushl 16(%%ebx) \n" // push retPtr on the stack
  1222. "call *12(%%ebx) \n"
  1223. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  1224. "addl $4, %%esp \n" // pop return pointer
  1225. #endif
  1226. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  1227. "addl 8(%%ebx), %%esp \n" // pop arguments
  1228. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  1229. "addl $4, %%esp \n" // pop the object pointer
  1230. #endif
  1231. #endif
  1232. #endif // AS_MINGW47
  1233. // Pop the alignment bytes
  1234. "popl %%esp \n"
  1235. "popl %%ebx \n"
  1236. #ifdef __OPTIMIZE__
  1237. // Epilogue
  1238. "movl %%ebp, %%esp \n"
  1239. ".cfi_def_cfa_register esp \n"
  1240. "popl %%ebp \n"
  1241. ".cfi_adjust_cfa_offset -4 \n"
  1242. ".cfi_restore ebp \n"
  1243. #endif
  1244. // Copy EAX:EDX to retQW. As the stack pointer has been
  1245. // restored it is now safe to access the local variable
  1246. "leal %1, %%ecx \n"
  1247. "movl %%eax, 0(%%ecx) \n"
  1248. "movl %%edx, 4(%%ecx) \n"
  1249. : // output
  1250. : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument
  1251. : "%eax", "%ecx" // clobber
  1252. );
  1253. #endif
  1254. return retQW;
  1255. }
  1256. asDWORD GetReturnedFloat()
  1257. {
  1258. asDWORD f;
  1259. #if defined ASM_INTEL
  1260. // Get the float value from ST0
  1261. __asm fstp dword ptr [f]
  1262. #elif defined ASM_AT_N_T
  1263. asm("fstps %0 \n" : "=m" (f));
  1264. #endif
  1265. return f;
  1266. }
  1267. asQWORD GetReturnedDouble()
  1268. {
  1269. asQWORD d;
  1270. #if defined ASM_INTEL
  1271. // Get the double value from ST0
  1272. __asm fstp qword ptr [d]
  1273. #elif defined ASM_AT_N_T
  1274. asm("fstpl %0 \n" : "=m" (d));
  1275. #endif
  1276. return d;
  1277. }
  1278. END_AS_NAMESPACE
  1279. #endif // AS_X86
  1280. #endif // AS_MAX_PORTABILITY