as_callfunc_x86.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2010 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 Öörni for Urho3D
  24. //
  25. // as_callfunc_x86.cpp
  26. //
  27. // These functions handle the actual calling of system functions
  28. //
  29. #include "as_config.h"
  30. #ifndef AS_MAX_PORTABILITY
  31. #ifdef AS_X86
  32. #include "as_callfunc.h"
  33. #include "as_scriptengine.h"
  34. #include "as_texts.h"
  35. #include "as_tokendef.h"
  36. BEGIN_AS_NAMESPACE
  37. typedef asQWORD (*t_CallCDeclQW)(const asDWORD *, int, size_t);
  38. typedef asQWORD (*t_CallCDeclQWObj)(void *obj, const asDWORD *, int, size_t);
  39. typedef asDWORD (*t_CallCDeclRetByRef)(const asDWORD *, int, size_t, void *);
  40. typedef asDWORD (*t_CallCDeclObjRetByRef)(void *obj, const asDWORD *, int, size_t, void *);
  41. typedef asQWORD (*t_CallSTDCallQW)(const asDWORD *, int, size_t);
  42. typedef asQWORD (*t_CallThisCallQW)(const void *, const asDWORD *, int, size_t);
  43. typedef asDWORD (*t_CallThisCallRetByRef)(const void *, const asDWORD *, int, size_t, void *);
  44. // Prototypes
  45. void CallCDeclFunction(const asDWORD *args, int paramSize, size_t func);
  46. void CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, size_t func);
  47. void CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, size_t func);
  48. void CallCDeclFunctionRetByRef_impl(const asDWORD *args, int paramSize, size_t func, void *retPtr);
  49. void CallCDeclFunctionRetByRefObjLast_impl(const void *obj, const asDWORD *args, int paramSize, size_t func, void *retPtr);
  50. void CallCDeclFunctionRetByRefObjFirst_impl(const void *obj, const asDWORD *args, int paramSize, size_t func, void *retPtr);
  51. void CallSTDCallFunction(const asDWORD *args, int paramSize, size_t func);
  52. void CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, size_t func);
  53. void CallThisCallFunctionRetByRef_impl(const void *, const asDWORD *, int, size_t, void *retPtr);
  54. // Initialize function pointers
  55. const t_CallCDeclQW CallCDeclFunctionQWord = (t_CallCDeclQW)CallCDeclFunction;
  56. const t_CallCDeclQWObj CallCDeclFunctionQWordObjLast = (t_CallCDeclQWObj)CallCDeclFunctionObjLast;
  57. const t_CallCDeclQWObj CallCDeclFunctionQWordObjFirst = (t_CallCDeclQWObj)CallCDeclFunctionObjFirst;
  58. const t_CallCDeclRetByRef CallCDeclFunctionRetByRef = (t_CallCDeclRetByRef)CallCDeclFunctionRetByRef_impl;
  59. const t_CallCDeclObjRetByRef CallCDeclFunctionRetByRefObjLast = (t_CallCDeclObjRetByRef)CallCDeclFunctionRetByRefObjLast_impl;
  60. const t_CallCDeclObjRetByRef CallCDeclFunctionRetByRefObjFirst = (t_CallCDeclObjRetByRef)CallCDeclFunctionRetByRefObjFirst_impl;
  61. const t_CallSTDCallQW CallSTDCallFunctionQWord = (t_CallSTDCallQW)CallSTDCallFunction;
  62. const t_CallThisCallQW CallThisCallFunctionQWord = (t_CallThisCallQW)CallThisCallFunction;
  63. const t_CallThisCallRetByRef CallThisCallFunctionRetByRef = (t_CallThisCallRetByRef)CallThisCallFunctionRetByRef_impl;
  64. asDWORD GetReturnedFloat();
  65. asQWORD GetReturnedDouble();
  66. int CallSystemFunction(int id, asCContext *context, void *objectPointer)
  67. {
  68. asCScriptEngine *engine = context->engine;
  69. asCScriptFunction *descr = engine->scriptFunctions[id];
  70. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  71. int callConv = sysFunc->callConv;
  72. if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
  73. return context->CallGeneric(id, objectPointer);
  74. asQWORD retQW = 0;
  75. void *func = (void*)sysFunc->func;
  76. int paramSize = sysFunc->paramSize;
  77. asDWORD *args = context->regs.stackPointer;
  78. void *retPointer = 0;
  79. void *obj = 0;
  80. asDWORD *vftable;
  81. int popSize = paramSize;
  82. context->regs.objectType = descr->returnType.GetObjectType();
  83. if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
  84. {
  85. // Allocate the memory for the object
  86. retPointer = engine->CallAlloc(descr->returnType.GetObjectType());
  87. if( sysFunc->hostReturnInMemory )
  88. {
  89. // The return is made in memory
  90. callConv++;
  91. }
  92. }
  93. if( callConv >= ICC_THISCALL )
  94. {
  95. if( objectPointer )
  96. {
  97. obj = objectPointer;
  98. }
  99. else
  100. {
  101. // The object pointer should be popped from the context stack
  102. popSize += AS_PTR_SIZE;
  103. // Check for null pointer
  104. obj = (void*)*(size_t*)(args);
  105. if( obj == 0 )
  106. {
  107. context->SetInternalException(TXT_NULL_POINTER_ACCESS);
  108. if( retPointer )
  109. engine->CallFree(retPointer);
  110. return 0;
  111. }
  112. // Add the base offset for multiple inheritance
  113. obj = (void*)(size_t(obj) + sysFunc->baseOffset);
  114. // Skip the object pointer
  115. args += AS_PTR_SIZE;
  116. }
  117. }
  118. asDWORD paramBuffer[64];
  119. if( sysFunc->takesObjByVal )
  120. {
  121. paramSize = 0;
  122. int spos = 0;
  123. int dpos = 1;
  124. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  125. {
  126. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  127. {
  128. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  129. if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
  130. {
  131. paramBuffer[dpos++] = args[spos++];
  132. paramSize++;
  133. }
  134. else
  135. #endif
  136. {
  137. // Copy the object's memory to the buffer
  138. memcpy(&paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
  139. // Delete the original memory
  140. engine->CallFree(*(char**)(args+spos));
  141. spos++;
  142. dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  143. paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
  144. }
  145. }
  146. else
  147. {
  148. // Copy the value directly
  149. paramBuffer[dpos++] = args[spos++];
  150. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  151. paramBuffer[dpos++] = args[spos++];
  152. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  153. }
  154. }
  155. // Keep a free location at the beginning
  156. args = &paramBuffer[1];
  157. }
  158. context->isCallingSystemFunction = true;
  159. switch( callConv )
  160. {
  161. case ICC_CDECL:
  162. retQW = CallCDeclFunctionQWord(args, paramSize<<2, (size_t)func);
  163. break;
  164. case ICC_CDECL_RETURNINMEM:
  165. retQW = CallCDeclFunctionRetByRef(args, paramSize<<2, (size_t)func, retPointer);
  166. break;
  167. case ICC_STDCALL:
  168. retQW = CallSTDCallFunctionQWord(args, paramSize<<2, (size_t)func);
  169. break;
  170. case ICC_STDCALL_RETURNINMEM:
  171. // Push the return pointer on the stack
  172. paramSize++;
  173. args--;
  174. *(size_t*)args = (size_t)retPointer;
  175. retQW = CallSTDCallFunctionQWord(args, paramSize<<2, (size_t)func);
  176. break;
  177. case ICC_THISCALL:
  178. retQW = CallThisCallFunctionQWord(obj, args, paramSize<<2, (size_t)func);
  179. break;
  180. case ICC_THISCALL_RETURNINMEM:
  181. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, (size_t)func, retPointer);
  182. break;
  183. case ICC_VIRTUAL_THISCALL:
  184. // Get virtual function table from the object pointer
  185. vftable = *(asDWORD**)obj;
  186. retQW = CallThisCallFunctionQWord(obj, args, paramSize<<2, vftable[size_t(func)>>2]);
  187. break;
  188. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  189. // Get virtual function table from the object pointer
  190. vftable = *(asDWORD**)obj;
  191. retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, vftable[size_t(func)>>2], retPointer);
  192. break;
  193. case ICC_CDECL_OBJLAST:
  194. retQW = CallCDeclFunctionQWordObjLast(obj, args, paramSize<<2, (size_t)func);
  195. break;
  196. case ICC_CDECL_OBJLAST_RETURNINMEM:
  197. // Call the system object method as a cdecl with the obj ref as the last parameter
  198. retQW = CallCDeclFunctionRetByRefObjLast(obj, args, paramSize<<2, (size_t)func, retPointer);
  199. break;
  200. case ICC_CDECL_OBJFIRST:
  201. // Call the system object method as a cdecl with the obj ref as the first parameter
  202. retQW = CallCDeclFunctionQWordObjFirst(obj, args, paramSize<<2, (size_t)func);
  203. break;
  204. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  205. // Call the system object method as a cdecl with the obj ref as the first parameter
  206. retQW = CallCDeclFunctionRetByRefObjFirst(obj, args, paramSize<<2, (size_t)func, retPointer);
  207. break;
  208. default:
  209. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  210. }
  211. context->isCallingSystemFunction = false;
  212. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  213. if( sysFunc->takesObjByVal )
  214. {
  215. // Need to free the complex objects passed by value
  216. args = context->regs.stackPointer;
  217. if( callConv >= ICC_THISCALL && !objectPointer )
  218. args++;
  219. int spos = 0;
  220. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  221. {
  222. if( descr->parameterTypes[n].IsObject() &&
  223. !descr->parameterTypes[n].IsReference() &&
  224. (descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
  225. {
  226. void *obj = (void*)args[spos++];
  227. asSTypeBehaviour *beh = &descr->parameterTypes[n].GetObjectType()->beh;
  228. if( beh->destruct )
  229. engine->CallObjectMethod(obj, beh->destruct);
  230. engine->CallFree(obj);
  231. }
  232. else
  233. spos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  234. }
  235. }
  236. #endif
  237. // Store the returned value in our stack
  238. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  239. {
  240. if( descr->returnType.IsObjectHandle() )
  241. {
  242. context->regs.objectRegister = (void*)(size_t)retQW;
  243. if( sysFunc->returnAutoHandle && context->regs.objectRegister )
  244. engine->CallObjectMethod(context->regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
  245. }
  246. else
  247. {
  248. if( !sysFunc->hostReturnInMemory )
  249. {
  250. // Copy the returned value to the pointer sent by the script engine
  251. if( sysFunc->hostReturnSize == 1 )
  252. *(asDWORD*)retPointer = (asDWORD)retQW;
  253. else
  254. *(asQWORD*)retPointer = retQW;
  255. }
  256. // Store the object in the register
  257. context->regs.objectRegister = retPointer;
  258. }
  259. }
  260. else
  261. {
  262. // Store value in value register
  263. if( sysFunc->hostReturnFloat )
  264. {
  265. if( sysFunc->hostReturnSize == 1 )
  266. *(asDWORD*)&context->regs.valueRegister = GetReturnedFloat();
  267. else
  268. context->regs.valueRegister = GetReturnedDouble();
  269. }
  270. else if( sysFunc->hostReturnSize == 1 )
  271. *(asDWORD*)&context->regs.valueRegister = (asDWORD)retQW;
  272. else
  273. context->regs.valueRegister = retQW;
  274. }
  275. if( sysFunc->hasAutoHandles )
  276. {
  277. args = context->regs.stackPointer;
  278. if( callConv >= ICC_THISCALL && !objectPointer )
  279. args++;
  280. int spos = 0;
  281. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  282. {
  283. if( sysFunc->paramAutoHandles[n] && args[spos] )
  284. {
  285. // Call the release method on the type
  286. engine->CallObjectMethod((void*)*(size_t*)&args[spos], descr->parameterTypes[n].GetObjectType()->beh.release);
  287. args[spos] = 0;
  288. }
  289. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  290. spos++;
  291. else
  292. spos += descr->parameterTypes[n].GetSizeOnStackDWords();
  293. }
  294. }
  295. return popSize;
  296. }
  297. // On GCC we need to prevent the compiler from inlining these assembler routines when
  298. // optimizing for speed (-O3), as the loop labels get duplicated which cause compile errors.
  299. #ifdef __GNUC__
  300. #define NOINLINE __attribute ((__noinline__))
  301. #else
  302. #define NOINLINE
  303. #endif
  304. void NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, size_t func)
  305. {
  306. #if defined ASM_INTEL
  307. // Copy the data to the real stack. If we fail to do
  308. // this we may run into trouble in case of exceptions.
  309. __asm
  310. {
  311. // We must save registers that are used
  312. push ecx
  313. // Clear the FPU stack, in case the called function doesn't do it by itself
  314. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  315. emms
  316. // Copy arguments from script
  317. // stack to application stack
  318. mov ecx, paramSize
  319. mov eax, args
  320. add eax, ecx
  321. cmp ecx, 0
  322. je endcopy
  323. copyloop:
  324. sub eax, 4
  325. push dword ptr [eax]
  326. sub ecx, 4
  327. jne copyloop
  328. endcopy:
  329. // Call function
  330. call [func]
  331. // Pop arguments from stack
  332. add esp, paramSize
  333. // Restore registers
  334. pop ecx
  335. // return value in EAX or EAX:EDX
  336. }
  337. #elif defined ASM_AT_N_T
  338. UNUSED_VAR(args);
  339. UNUSED_VAR(paramSize);
  340. UNUSED_VAR(func);
  341. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  342. asm("pushl %ecx \n"
  343. "emms \n"
  344. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  345. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  346. // to calculate how much we will put on the stack during this call.
  347. "movl 12(%ebp), %eax \n" // paramSize
  348. "addl $4, %eax \n" // counting esp that we will push on the stack
  349. "movl %esp, %ecx \n"
  350. "subl %eax, %ecx \n"
  351. "andl $15, %ecx \n"
  352. "movl %esp, %eax \n"
  353. "subl %ecx, %esp \n"
  354. "pushl %eax \n" // Store the original stack pointer
  355. "movl 12(%ebp), %ecx \n" // paramSize
  356. "movl 8(%ebp), %eax \n" // args
  357. "addl %ecx, %eax \n" // push arguments on the stack
  358. "cmp $0, %ecx \n"
  359. "je endcopy \n"
  360. "copyloop: \n"
  361. "subl $4, %eax \n"
  362. "pushl (%eax) \n"
  363. "subl $4, %ecx \n"
  364. "jne copyloop \n"
  365. "endcopy: \n"
  366. "call *16(%ebp) \n"
  367. "addl 12(%ebp), %esp \n" // pop arguments
  368. // Pop the alignment bytes
  369. "popl %esp \n"
  370. "popl %ecx \n");
  371. #endif
  372. }
  373. void NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, size_t func)
  374. {
  375. #if defined ASM_INTEL
  376. // Copy the data to the real stack. If we fail to do
  377. // this we may run into trouble in case of exceptions.
  378. __asm
  379. {
  380. // We must save registers that are used
  381. push ecx
  382. // Clear the FPU stack, in case the called function doesn't do it by itself
  383. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  384. emms
  385. // Push the object pointer as the last argument to the function
  386. push obj
  387. // Copy arguments from script
  388. // stack to application stack
  389. mov ecx, paramSize
  390. mov eax, args
  391. add eax, ecx
  392. cmp ecx, 0
  393. je endcopy
  394. copyloop:
  395. sub eax, 4
  396. push dword ptr [eax]
  397. sub ecx, 4
  398. jne copyloop
  399. endcopy:
  400. // Call function
  401. call [func]
  402. // Pop arguments from stack
  403. add esp, paramSize
  404. add esp, 4
  405. // Restore registers
  406. pop ecx
  407. // return value in EAX or EAX:EDX
  408. }
  409. #elif defined ASM_AT_N_T
  410. UNUSED_VAR(obj);
  411. UNUSED_VAR(args);
  412. UNUSED_VAR(paramSize);
  413. UNUSED_VAR(func);
  414. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  415. asm("pushl %ecx \n"
  416. "emms \n"
  417. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  418. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  419. // to calculate how much we will put on the stack during this call.
  420. "movl 16(%ebp), %eax \n" // paramSize
  421. "addl $8, %eax \n" // counting esp that we will push on the stack
  422. "movl %esp, %ecx \n"
  423. "subl %eax, %ecx \n"
  424. "andl $15, %ecx \n"
  425. "movl %esp, %eax \n"
  426. "subl %ecx, %esp \n"
  427. "pushl %eax \n" // Store the original stack pointer
  428. "pushl 8(%ebp) \n"
  429. "movl 16(%ebp), %ecx \n" // paramSize
  430. "movl 12(%ebp), %eax \n" // args
  431. "addl %ecx, %eax \n" // push arguments on the stack
  432. "cmp $0, %ecx \n"
  433. "je endcopy8 \n"
  434. "copyloop8: \n"
  435. "subl $4, %eax \n"
  436. "pushl (%eax) \n"
  437. "subl $4, %ecx \n"
  438. "jne copyloop8 \n"
  439. "endcopy8: \n"
  440. "call *20(%ebp) \n"
  441. "addl 16(%ebp), %esp \n" // pop arguments
  442. "addl $4, %esp \n"
  443. // Pop the alignment bytes
  444. "popl %esp \n"
  445. "popl %ecx \n");
  446. #endif
  447. }
  448. void NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, size_t func)
  449. {
  450. #if defined ASM_INTEL
  451. // Copy the data to the real stack. If we fail to do
  452. // this we may run into trouble in case of exceptions.
  453. __asm
  454. {
  455. // We must save registers that are used
  456. push ecx
  457. // Clear the FPU stack, in case the called function doesn't do it by itself
  458. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  459. emms
  460. // Copy arguments from script
  461. // stack to application stack
  462. mov ecx, paramSize
  463. mov eax, args
  464. add eax, ecx
  465. cmp ecx, 0
  466. je endcopy
  467. copyloop:
  468. sub eax, 4
  469. push dword ptr [eax]
  470. sub ecx, 4
  471. jne copyloop
  472. endcopy:
  473. // push object as first parameter
  474. push obj
  475. // Call function
  476. call [func]
  477. // Pop arguments from stack
  478. add esp, paramSize
  479. add esp, 4
  480. // Restore registers
  481. pop ecx
  482. // return value in EAX or EAX:EDX
  483. }
  484. #elif defined ASM_AT_N_T
  485. UNUSED_VAR(obj);
  486. UNUSED_VAR(args);
  487. UNUSED_VAR(paramSize);
  488. UNUSED_VAR(func);
  489. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  490. asm("pushl %ecx \n"
  491. "emms \n"
  492. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  493. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  494. // to calculate how much we will put on the stack during this call.
  495. "movl 16(%ebp), %eax \n" // paramSize
  496. "addl $8, %eax \n" // counting esp that we will push on the stack
  497. "movl %esp, %ecx \n"
  498. "subl %eax, %ecx \n"
  499. "andl $15, %ecx \n"
  500. "movl %esp, %eax \n"
  501. "subl %ecx, %esp \n"
  502. "pushl %eax \n" // Store the original stack pointer
  503. "movl 16(%ebp), %ecx \n" // paramSize
  504. "movl 12(%ebp), %eax \n" // args
  505. "addl %ecx, %eax \n" // push arguments on the stack
  506. "cmp $0, %ecx \n"
  507. "je endcopy6 \n"
  508. "copyloop6: \n"
  509. "subl $4, %eax \n"
  510. "pushl (%eax) \n"
  511. "subl $4, %ecx \n"
  512. "jne copyloop6 \n"
  513. "endcopy6: \n"
  514. "pushl 8(%ebp) \n" // push obj
  515. "call *20(%ebp) \n"
  516. "addl 16(%ebp), %esp \n" // pop arguments
  517. "addl $4, %esp \n"
  518. // Pop the alignment bytes
  519. "popl %esp \n"
  520. "popl %ecx \n");
  521. #endif
  522. }
  523. void NOINLINE CallCDeclFunctionRetByRefObjFirst_impl(const void *obj, const asDWORD *args, int paramSize, size_t func, void *retPtr)
  524. {
  525. #if defined ASM_INTEL
  526. // Copy the data to the real stack. If we fail to do
  527. // this we may run into trouble in case of exceptions.
  528. __asm
  529. {
  530. // We must save registers that are used
  531. push ecx
  532. // Clear the FPU stack, in case the called function doesn't do it by itself
  533. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  534. emms
  535. // Copy arguments from script
  536. // stack to application stack
  537. mov ecx, paramSize
  538. mov eax, args
  539. add eax, ecx
  540. cmp ecx, 0
  541. je endcopy
  542. copyloop:
  543. sub eax, 4
  544. push dword ptr [eax]
  545. sub ecx, 4
  546. jne copyloop
  547. endcopy:
  548. // Push the object pointer
  549. push obj
  550. // Push the return pointer
  551. push retPtr;
  552. // Call function
  553. call [func]
  554. // Pop arguments from stack
  555. add esp, paramSize
  556. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  557. // Pop the return pointer
  558. add esp, 8
  559. #else
  560. add esp, 4
  561. #endif
  562. // Restore registers
  563. pop ecx
  564. // return value in EAX or EAX:EDX
  565. }
  566. #elif defined ASM_AT_N_T
  567. UNUSED_VAR(obj);
  568. UNUSED_VAR(args);
  569. UNUSED_VAR(paramSize);
  570. UNUSED_VAR(func);
  571. UNUSED_VAR(retPtr);
  572. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  573. asm("pushl %ecx \n"
  574. "emms \n"
  575. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  576. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  577. // to calculate how much we will put on the stack during this call.
  578. "movl 16(%ebp), %eax \n" // paramSize
  579. "addl $12, %eax \n" // counting esp that we will push on the stack
  580. "movl %esp, %ecx \n"
  581. "subl %eax, %ecx \n"
  582. "andl $15, %ecx \n"
  583. "movl %esp, %eax \n"
  584. "subl %ecx, %esp \n"
  585. "pushl %eax \n" // Store the original stack pointer
  586. "movl 16(%ebp), %ecx \n" // paramSize
  587. "movl 12(%ebp), %eax \n" // args
  588. "addl %ecx, %eax \n" // push arguments on the stack
  589. "cmp $0, %ecx \n"
  590. "je endcopy5 \n"
  591. "copyloop5: \n"
  592. "subl $4, %eax \n"
  593. "pushl (%eax) \n"
  594. "subl $4, %ecx \n"
  595. "jne copyloop5 \n"
  596. "endcopy5: \n"
  597. "pushl 8(%ebp) \n" // push object first
  598. "pushl 24(%ebp) \n" // retPtr
  599. "call *20(%ebp) \n" // func
  600. "addl 16(%ebp), %esp \n" // pop arguments
  601. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  602. "addl $8, %esp \n" // Pop the return pointer and object pointer
  603. #else
  604. "addl $4, %esp \n" // Pop the object pointer
  605. #endif
  606. // Pop the alignment bytes
  607. "popl %esp \n"
  608. "popl %ecx \n");
  609. #endif
  610. }
  611. void NOINLINE CallCDeclFunctionRetByRef_impl(const asDWORD *args, int paramSize, size_t func, void *retPtr)
  612. {
  613. #if defined ASM_INTEL
  614. // Copy the data to the real stack. If we fail to do
  615. // this we may run into trouble in case of exceptions.
  616. __asm
  617. {
  618. // We must save registers that are used
  619. push ecx
  620. // Clear the FPU stack, in case the called function doesn't do it by itself
  621. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  622. emms
  623. // Copy arguments from script
  624. // stack to application stack
  625. mov ecx, paramSize
  626. mov eax, args
  627. add eax, ecx
  628. cmp ecx, 0
  629. je endcopy
  630. copyloop:
  631. sub eax, 4
  632. push dword ptr [eax]
  633. sub ecx, 4
  634. jne copyloop
  635. endcopy:
  636. // Push the return pointer
  637. push retPtr;
  638. // Call function
  639. call [func]
  640. // Pop arguments from stack
  641. add esp, paramSize
  642. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  643. // Pop the return pointer
  644. add esp, 4
  645. #endif
  646. // Restore registers
  647. pop ecx
  648. // return value in EAX or EAX:EDX
  649. }
  650. #elif defined ASM_AT_N_T
  651. UNUSED_VAR(args);
  652. UNUSED_VAR(paramSize);
  653. UNUSED_VAR(func);
  654. UNUSED_VAR(retPtr);
  655. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  656. asm("pushl %ecx \n"
  657. "emms \n"
  658. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  659. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  660. // to calculate how much we will put on the stack during this call.
  661. "movl 12(%ebp), %eax \n" // paramSize
  662. "addl $8, %eax \n" // counting esp that we will push on the stack
  663. "movl %esp, %ecx \n"
  664. "subl %eax, %ecx \n"
  665. "andl $15, %ecx \n"
  666. "movl %esp, %eax \n"
  667. "subl %ecx, %esp \n"
  668. "pushl %eax \n" // Store the original stack pointer
  669. "movl 12(%ebp), %ecx \n" // paramSize
  670. "movl 8(%ebp), %eax \n" // args
  671. "addl %ecx, %eax \n" // push arguments on the stack
  672. "cmp $0, %ecx \n"
  673. "je endcopy7 \n"
  674. "copyloop7: \n"
  675. "subl $4, %eax \n"
  676. "pushl (%eax) \n"
  677. "subl $4, %ecx \n"
  678. "jne copyloop7 \n"
  679. "endcopy7: \n"
  680. "pushl 20(%ebp) \n" // retPtr
  681. "call *16(%ebp) \n" // func
  682. "addl 12(%ebp), %esp \n" // pop arguments
  683. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  684. "addl $4, %esp \n" // Pop the return pointer
  685. #endif
  686. // Pop the alignment bytes
  687. "popl %esp \n"
  688. "popl %ecx \n");
  689. #endif
  690. }
  691. void NOINLINE CallCDeclFunctionRetByRefObjLast_impl(const void *obj, const asDWORD *args, int paramSize, size_t func, void *retPtr)
  692. {
  693. #if defined ASM_INTEL
  694. // Copy the data to the real stack. If we fail to do
  695. // this we may run into trouble in case of exceptions.
  696. __asm
  697. {
  698. // We must save registers that are used
  699. push ecx
  700. // Clear the FPU stack, in case the called function doesn't do it by itself
  701. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  702. emms
  703. push obj
  704. // Copy arguments from script
  705. // stack to application stack
  706. mov ecx, paramSize
  707. mov eax, args
  708. add eax, ecx
  709. cmp ecx, 0
  710. je endcopy
  711. copyloop:
  712. sub eax, 4
  713. push dword ptr [eax]
  714. sub ecx, 4
  715. jne copyloop
  716. endcopy:
  717. // Push the return pointer
  718. push retPtr;
  719. // Call function
  720. call [func]
  721. // Pop arguments from stack
  722. add esp, paramSize
  723. add esp, 4
  724. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  725. // Pop the return pointer
  726. add esp, 4
  727. #endif
  728. // Restore registers
  729. pop ecx
  730. // return value in EAX or EAX:EDX
  731. }
  732. #elif defined ASM_AT_N_T
  733. UNUSED_VAR(obj);
  734. UNUSED_VAR(args);
  735. UNUSED_VAR(paramSize);
  736. UNUSED_VAR(func);
  737. UNUSED_VAR(retPtr);
  738. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  739. asm("pushl %ecx \n"
  740. "emms \n"
  741. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  742. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  743. // to calculate how much we will put on the stack during this call.
  744. "movl 16(%ebp), %eax \n" // paramSize
  745. "addl $12, %eax \n" // counting esp that we will push on the stack
  746. "movl %esp, %ecx \n"
  747. "subl %eax, %ecx \n"
  748. "andl $15, %ecx \n"
  749. "movl %esp, %eax \n"
  750. "subl %ecx, %esp \n"
  751. "pushl %eax \n" // Store the original stack pointer
  752. "pushl 8(%ebp) \n"
  753. "movl 16(%ebp), %ecx \n" // paramSize
  754. "movl 12(%ebp), %eax \n" // args
  755. "addl %ecx, %eax \n" // push arguments on the stack
  756. "cmp $0, %ecx \n"
  757. "je endcopy4 \n"
  758. "copyloop4: \n"
  759. "subl $4, %eax \n"
  760. "pushl (%eax) \n"
  761. "subl $4, %ecx \n"
  762. "jne copyloop4 \n"
  763. "endcopy4: \n"
  764. "pushl 24(%ebp) \n" // retPtr
  765. "call *20(%ebp) \n" // func
  766. "addl 16(%ebp), %esp \n" // pop arguments
  767. #ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER
  768. "addl $8, %esp \n" // Pop the return pointer
  769. #else
  770. "addl $4, %esp \n" // Pop the return pointer
  771. #endif
  772. // Pop the alignment bytes
  773. "popl %esp \n"
  774. "popl %ecx \n");
  775. #endif
  776. }
  777. void NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, size_t func)
  778. {
  779. #if defined ASM_INTEL
  780. // Copy the data to the real stack. If we fail to do
  781. // this we may run into trouble in case of exceptions.
  782. __asm
  783. {
  784. // We must save registers that are used
  785. push ecx
  786. // Clear the FPU stack, in case the called function doesn't do it by itself
  787. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  788. emms
  789. // Copy arguments from script
  790. // stack to application stack
  791. mov ecx, paramSize
  792. mov eax, args
  793. add eax, ecx
  794. cmp ecx, 0
  795. je endcopy
  796. copyloop:
  797. sub eax, 4
  798. push dword ptr [eax]
  799. sub ecx, 4
  800. jne copyloop
  801. endcopy:
  802. // Call function
  803. call [func]
  804. // The callee already removed parameters from the stack
  805. // Restore registers
  806. pop ecx
  807. // return value in EAX or EAX:EDX
  808. }
  809. #elif defined ASM_AT_N_T
  810. UNUSED_VAR(args);
  811. UNUSED_VAR(paramSize);
  812. UNUSED_VAR(func);
  813. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  814. asm("pushl %ecx \n"
  815. "emms \n"
  816. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  817. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  818. // to calculate how much we will put on the stack during this call.
  819. "movl 12(%ebp), %eax \n" // paramSize
  820. "addl $4, %eax \n" // counting esp that we will push on the stack
  821. "movl %esp, %ecx \n"
  822. "subl %eax, %ecx \n"
  823. "andl $15, %ecx \n"
  824. "movl %esp, %eax \n"
  825. "subl %ecx, %esp \n"
  826. "pushl %eax \n" // Store the original stack pointer
  827. "movl 12(%ebp), %ecx \n" // paramSize
  828. "movl 8(%ebp), %eax \n" // args
  829. "addl %ecx, %eax \n" // push arguments on the stack
  830. "cmp $0, %ecx \n"
  831. "je endcopy2 \n"
  832. "copyloop2: \n"
  833. "subl $4, %eax \n"
  834. "pushl (%eax) \n"
  835. "subl $4, %ecx \n"
  836. "jne copyloop2 \n"
  837. "endcopy2: \n"
  838. "call *16(%ebp) \n" // callee pops the arguments
  839. // Pop the alignment bytes
  840. "popl %esp \n"
  841. "popl %ecx \n");
  842. #endif
  843. }
  844. void NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, size_t func)
  845. {
  846. #if defined ASM_INTEL
  847. // Copy the data to the real stack. If we fail to do
  848. // this we may run into trouble in case of exceptions.
  849. __asm
  850. {
  851. // We must save registers that are used
  852. push ecx
  853. // Clear the FPU stack, in case the called function doesn't do it by itself
  854. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  855. emms
  856. // Copy arguments from script
  857. // stack to application stack
  858. mov ecx, paramSize
  859. mov eax, args
  860. add eax, ecx
  861. cmp ecx, 0
  862. je endcopy
  863. copyloop:
  864. sub eax, 4
  865. push dword ptr [eax]
  866. sub ecx, 4
  867. jne copyloop
  868. endcopy:
  869. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  870. // Push the object pointer on the stack
  871. push obj
  872. #else
  873. // Move object pointer to ECX
  874. mov ecx, obj
  875. #endif
  876. // Call function
  877. call [func]
  878. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  879. // Pop arguments
  880. add esp, paramSize
  881. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  882. // Pop object pointer
  883. add esp, 4
  884. #endif
  885. #endif
  886. // Restore registers
  887. pop ecx
  888. // Return value in EAX or EAX:EDX
  889. }
  890. #elif defined ASM_AT_N_T
  891. UNUSED_VAR(obj);
  892. UNUSED_VAR(args);
  893. UNUSED_VAR(paramSize);
  894. UNUSED_VAR(func);
  895. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  896. asm("pushl %ecx \n"
  897. "emms \n"
  898. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  899. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  900. // to calculate how much we will put on the stack during this call.
  901. "movl 16(%ebp), %eax \n" // paramSize
  902. "addl $8, %eax \n" // counting esp that we will push on the stack
  903. "movl %esp, %ecx \n"
  904. "subl %eax, %ecx \n"
  905. "andl $15, %ecx \n"
  906. "movl %esp, %eax \n"
  907. "subl %ecx, %esp \n"
  908. "pushl %eax \n" // Store the original stack pointer
  909. "movl 16(%ebp), %ecx \n" // paramSize
  910. "movl 12(%ebp), %eax \n" // args
  911. "addl %ecx, %eax \n" // push all arguments on the stack
  912. "cmp $0, %ecx \n"
  913. "je endcopy1 \n"
  914. "copyloop1: \n"
  915. "subl $4, %eax \n"
  916. "pushl (%eax) \n"
  917. "subl $4, %ecx \n"
  918. "jne copyloop1 \n"
  919. "endcopy1: \n"
  920. "movl 8(%ebp), %ecx \n" // move obj into ECX
  921. "pushl 8(%ebp) \n" // push obj on the stack
  922. "call *20(%ebp) \n"
  923. "addl 16(%ebp), %esp \n" // pop arguments
  924. "addl $4, %esp \n" // pop obj
  925. // Pop the alignment bytes
  926. "popl %esp \n"
  927. "popl %ecx \n");
  928. #endif
  929. }
  930. void NOINLINE CallThisCallFunctionRetByRef_impl(const void *obj, const asDWORD *args, int paramSize, size_t func, void *retPtr)
  931. {
  932. #if defined ASM_INTEL
  933. // Copy the data to the real stack. If we fail to do
  934. // this we may run into trouble in case of exceptions.
  935. __asm
  936. {
  937. // We must save registers that are used
  938. push ecx
  939. // Clear the FPU stack, in case the called function doesn't do it by itself
  940. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  941. emms
  942. // Copy arguments from script
  943. // stack to application stack
  944. mov ecx, paramSize
  945. mov eax, args
  946. add eax, ecx
  947. cmp ecx, 0
  948. je endcopy
  949. copyloop:
  950. sub eax, 4
  951. push dword ptr [eax]
  952. sub ecx, 4
  953. jne copyloop
  954. endcopy:
  955. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  956. // Push the object pointer on the stack
  957. push obj
  958. #else
  959. // Move object pointer to ECX
  960. mov ecx, obj
  961. #endif
  962. // Push the return pointer
  963. push retPtr
  964. // Call function
  965. call [func]
  966. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  967. // Pop the return pointer
  968. add esp, 4
  969. #endif
  970. #ifndef THISCALL_CALLEE_POPS_ARGUMENTS
  971. // Pop arguments
  972. add esp, paramSize
  973. #ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK
  974. // Pop object pointer
  975. add esp, 4
  976. #endif
  977. #endif
  978. // Restore registers
  979. pop ecx
  980. // Return value in EAX or EAX:EDX
  981. }
  982. #elif defined ASM_AT_N_T
  983. UNUSED_VAR(obj);
  984. UNUSED_VAR(args);
  985. UNUSED_VAR(paramSize);
  986. UNUSED_VAR(func);
  987. UNUSED_VAR(retPtr);
  988. // Urho3D: modified to use EMMS instead to not modify the floating point control word
  989. asm("pushl %ecx \n"
  990. "emms \n"
  991. // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
  992. // It is assumed that when entering this function, the stack pointer is already aligned, so we need
  993. // to calculate how much we will put on the stack during this call.
  994. "movl 16(%ebp), %eax \n" // paramSize
  995. "addl $12, %eax \n" // counting esp that we will push on the stack
  996. "movl %esp, %ecx \n"
  997. "subl %eax, %ecx \n"
  998. "andl $15, %ecx \n"
  999. "movl %esp, %eax \n"
  1000. "subl %ecx, %esp \n"
  1001. "pushl %eax \n" // Store the original stack pointer
  1002. "movl 16(%ebp), %ecx \n" // paramSize
  1003. "movl 12(%ebp), %eax \n" // args
  1004. "addl %ecx, %eax \n" // push all arguments to the stack
  1005. "cmp $0, %ecx \n"
  1006. "je endcopy3 \n"
  1007. "copyloop3: \n"
  1008. "subl $4, %eax \n"
  1009. "pushl (%eax) \n"
  1010. "subl $4, %ecx \n"
  1011. "jne copyloop3 \n"
  1012. "endcopy3: \n"
  1013. "movl 8(%ebp), %ecx \n" // move obj into ECX
  1014. "pushl 8(%ebp) \n" // push obj on the stack
  1015. "pushl 24(%ebp) \n" // push retPtr on the stack
  1016. "call *20(%ebp) \n"
  1017. #ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER
  1018. "addl $4, %esp \n" // pop return pointer
  1019. #endif
  1020. "addl 16(%ebp), %esp \n" // pop arguments
  1021. "addl $4, %esp \n" // pop the object pointer
  1022. // the return pointer was popped by the callee
  1023. // Pop the alignment bytes
  1024. "popl %esp \n"
  1025. "popl %ecx \n");
  1026. #endif
  1027. }
  1028. asDWORD GetReturnedFloat()
  1029. {
  1030. asDWORD f;
  1031. #if defined ASM_INTEL
  1032. // Get the float value from ST0
  1033. __asm fstp dword ptr [f]
  1034. #elif defined ASM_AT_N_T
  1035. asm("fstps %0 \n" : "=m" (f));
  1036. #endif
  1037. return f;
  1038. }
  1039. asQWORD GetReturnedDouble()
  1040. {
  1041. asQWORD d;
  1042. #if defined ASM_INTEL
  1043. // Get the double value from ST0
  1044. __asm fstp qword ptr [d]
  1045. #elif defined ASM_AT_N_T
  1046. asm("fstpl %0 \n" : "=m" (d));
  1047. #endif
  1048. return d;
  1049. }
  1050. END_AS_NAMESPACE
  1051. #endif // AS_X86
  1052. #endif // AS_MAX_PORTABILITY