as_callfunc_x86.cpp 46 KB

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