as_callfunc_x86.cpp 45 KB

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