as_callfunc.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2015 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. //
  24. // as_callfunc.cpp
  25. //
  26. // These functions handle the actual calling of system functions
  27. //
  28. #include "as_config.h"
  29. #include "as_callfunc.h"
  30. #include "as_scriptengine.h"
  31. #include "as_texts.h"
  32. #include "as_context.h"
  33. BEGIN_AS_NAMESPACE
  34. // ref: Member Function Pointers and the Fastest Possible C++ Delegates
  35. // describes the structure of class method pointers for most compilers
  36. // http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
  37. // ref: The code comments for ItaniumCXXABI::EmitLoadOfMemberFunctionPointer in the LLVM compiler
  38. // describes the structure for class method pointers on Itanium and arm64 ABI
  39. // http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937
  40. int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *objForThiscall, asSSystemFunctionInterface *internal)
  41. {
  42. memset(internal, 0, sizeof(asSSystemFunctionInterface));
  43. internal->func = ptr.ptr.f.func;
  44. internal->objForThiscall = 0;
  45. // Was a compatible calling convention specified?
  46. if( internal->func )
  47. {
  48. if( ptr.flag == 1 && callConv != asCALL_GENERIC )
  49. return asWRONG_CALLING_CONV;
  50. else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
  51. return asWRONG_CALLING_CONV;
  52. else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) )
  53. return asWRONG_CALLING_CONV;
  54. }
  55. asDWORD base = callConv;
  56. if( !isMethod )
  57. {
  58. if( base == asCALL_CDECL )
  59. internal->callConv = ICC_CDECL;
  60. else if( base == asCALL_STDCALL )
  61. internal->callConv = ICC_STDCALL;
  62. else if( base == asCALL_THISCALL_ASGLOBAL )
  63. {
  64. if( objForThiscall == 0 )
  65. return asINVALID_ARG;
  66. internal->objForThiscall = objForThiscall;
  67. internal->callConv = ICC_THISCALL;
  68. // This is really a thiscall, so it is necessary to check for virtual method pointers
  69. base = asCALL_THISCALL;
  70. isMethod = true;
  71. }
  72. else if( base == asCALL_GENERIC )
  73. internal->callConv = ICC_GENERIC_FUNC;
  74. else
  75. return asNOT_SUPPORTED;
  76. }
  77. if( isMethod )
  78. {
  79. #ifndef AS_NO_CLASS_METHODS
  80. if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST )
  81. {
  82. internalCallConv thisCallConv;
  83. if( base == asCALL_THISCALL )
  84. {
  85. if( callConv != asCALL_THISCALL_ASGLOBAL && objForThiscall )
  86. return asINVALID_ARG;
  87. thisCallConv = ICC_THISCALL;
  88. }
  89. else
  90. {
  91. #ifdef AS_NO_THISCALL_FUNCTOR_METHOD
  92. return asNOT_SUPPORTED;
  93. #else
  94. if( objForThiscall == 0 )
  95. return asINVALID_ARG;
  96. internal->objForThiscall = objForThiscall;
  97. if( base == asCALL_THISCALL_OBJFIRST )
  98. thisCallConv = ICC_THISCALL_OBJFIRST;
  99. else //if( base == asCALL_THISCALL_OBJLAST )
  100. thisCallConv = ICC_THISCALL_OBJLAST;
  101. #endif
  102. }
  103. internal->callConv = thisCallConv;
  104. #ifdef GNU_STYLE_VIRTUAL_METHOD
  105. if( (size_t(ptr.ptr.f.func) & 1) )
  106. internal->callConv = (internalCallConv)(thisCallConv + 2);
  107. #endif
  108. internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr);
  109. #if (defined(AS_ARM) || defined(AS_MIPS)) && (defined(__GNUC__) || defined(AS_PSVITA))
  110. // As the least significant bit in func is used to switch to THUMB mode
  111. // on ARM processors, the LSB in the __delta variable is used instead of
  112. // the one in __pfn on ARM processors.
  113. // MIPS also appear to use the base offset to indicate virtual method.
  114. if( (size_t(internal->baseOffset) & 1) )
  115. internal->callConv = (internalCallConv)(thisCallConv + 2);
  116. #endif
  117. #ifdef HAVE_VIRTUAL_BASE_OFFSET
  118. // We don't support virtual inheritance
  119. if( VIRTUAL_BASE_OFFSET(ptr) != 0 )
  120. return asNOT_SUPPORTED;
  121. #endif
  122. }
  123. else
  124. #endif
  125. if( base == asCALL_CDECL_OBJLAST )
  126. internal->callConv = ICC_CDECL_OBJLAST;
  127. else if( base == asCALL_CDECL_OBJFIRST )
  128. internal->callConv = ICC_CDECL_OBJFIRST;
  129. else if( base == asCALL_GENERIC )
  130. internal->callConv = ICC_GENERIC_METHOD;
  131. else
  132. return asNOT_SUPPORTED;
  133. }
  134. return 0;
  135. }
  136. // This function should prepare system functions so that it will be faster to call them
  137. int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine * /*engine*/)
  138. {
  139. asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC);
  140. // Calculate the size needed for the parameters
  141. internal->paramSize = func->GetSpaceNeededForArguments();
  142. // Prepare the clean up instructions for the function arguments
  143. internal->cleanArgs.SetLength(0);
  144. int offset = 0;
  145. for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ )
  146. {
  147. asCDataType &dt = func->parameterTypes[n];
  148. if( dt.IsObject() && !dt.IsReference() )
  149. {
  150. asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
  151. if( dt.GetObjectType()->flags & asOBJ_REF )
  152. {
  153. asASSERT( (dt.GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release );
  154. if( beh->release )
  155. {
  156. asSSystemFunctionInterface::SClean clean;
  157. clean.op = 0; // call release
  158. clean.ot = dt.GetObjectType();
  159. clean.off = short(offset);
  160. internal->cleanArgs.PushLast(clean);
  161. }
  162. }
  163. else
  164. {
  165. asSSystemFunctionInterface::SClean clean;
  166. clean.op = 1; // call free
  167. clean.ot = dt.GetObjectType();
  168. clean.off = short(offset);
  169. // Call the destructor then free the memory
  170. if( beh->destruct )
  171. clean.op = 2; // call destruct, then free
  172. internal->cleanArgs.PushLast(clean);
  173. }
  174. }
  175. if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
  176. offset += AS_PTR_SIZE;
  177. else
  178. offset += dt.GetSizeOnStackDWords();
  179. }
  180. return 0;
  181. }
  182. // This function should prepare system functions so that it will be faster to call them
  183. int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine)
  184. {
  185. #ifdef AS_MAX_PORTABILITY
  186. UNUSED_VAR(func);
  187. UNUSED_VAR(internal);
  188. UNUSED_VAR(engine);
  189. // This should never happen, as when AS_MAX_PORTABILITY is on, all functions
  190. // are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric
  191. asASSERT(false);
  192. #else
  193. // References are always returned as primitive data
  194. if( func->returnType.IsReference() || func->returnType.IsObjectHandle() )
  195. {
  196. internal->hostReturnInMemory = false;
  197. internal->hostReturnSize = sizeof(void*)/4;
  198. internal->hostReturnFloat = false;
  199. }
  200. // Registered types have special flags that determine how they are returned
  201. else if( func->returnType.IsObject() )
  202. {
  203. asDWORD objType = func->returnType.GetObjectType()->flags;
  204. // Only value types can be returned by value
  205. asASSERT( objType & asOBJ_VALUE );
  206. if( !(objType & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
  207. {
  208. // If the return is by value then we need to know the true type
  209. engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
  210. asCString str;
  211. str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetObjectType()->name.AddressOf());
  212. engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  213. engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
  214. }
  215. else if( objType & asOBJ_APP_ARRAY )
  216. {
  217. // Array types are always returned in memory
  218. internal->hostReturnInMemory = true;
  219. internal->hostReturnSize = sizeof(void*)/4;
  220. internal->hostReturnFloat = false;
  221. }
  222. else if( objType & asOBJ_APP_CLASS )
  223. {
  224. internal->hostReturnFloat = false;
  225. if( objType & COMPLEX_RETURN_MASK )
  226. {
  227. internal->hostReturnInMemory = true;
  228. internal->hostReturnSize = sizeof(void*)/4;
  229. }
  230. else
  231. {
  232. #ifdef HAS_128_BIT_PRIMITIVES
  233. if( func->returnType.GetSizeInMemoryDWords() > 4 )
  234. #else
  235. if( func->returnType.GetSizeInMemoryDWords() > 2 )
  236. #endif
  237. {
  238. internal->hostReturnInMemory = true;
  239. internal->hostReturnSize = sizeof(void*)/4;
  240. }
  241. else
  242. {
  243. internal->hostReturnInMemory = false;
  244. internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
  245. #ifdef SPLIT_OBJS_BY_MEMBER_TYPES
  246. if( func->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS )
  247. internal->hostReturnFloat = true;
  248. #endif
  249. }
  250. #ifdef THISCALL_RETURN_SIMPLE_IN_MEMORY
  251. if((internal->callConv == ICC_THISCALL ||
  252. #ifdef AS_NO_THISCALL_FUNCTOR_METHOD
  253. internal->callConv == ICC_VIRTUAL_THISCALL) &&
  254. #else
  255. internal->callConv == ICC_VIRTUAL_THISCALL ||
  256. internal->callConv == ICC_THISCALL_OBJFIRST ||
  257. internal->callConv == ICC_THISCALL_OBJLAST) &&
  258. #endif
  259. func->returnType.GetSizeInMemoryDWords() >= THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
  260. {
  261. internal->hostReturnInMemory = true;
  262. internal->hostReturnSize = sizeof(void*)/4;
  263. }
  264. #endif
  265. #ifdef CDECL_RETURN_SIMPLE_IN_MEMORY
  266. if((internal->callConv == ICC_CDECL ||
  267. internal->callConv == ICC_CDECL_OBJLAST ||
  268. internal->callConv == ICC_CDECL_OBJFIRST) &&
  269. func->returnType.GetSizeInMemoryDWords() >= CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
  270. {
  271. internal->hostReturnInMemory = true;
  272. internal->hostReturnSize = sizeof(void*)/4;
  273. }
  274. #endif
  275. #ifdef STDCALL_RETURN_SIMPLE_IN_MEMORY
  276. if( internal->callConv == ICC_STDCALL &&
  277. func->returnType.GetSizeInMemoryDWords() >= STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE)
  278. {
  279. internal->hostReturnInMemory = true;
  280. internal->hostReturnSize = sizeof(void*)/4;
  281. }
  282. #endif
  283. }
  284. #ifdef SPLIT_OBJS_BY_MEMBER_TYPES
  285. // It's not safe to return objects by value because different registers
  286. // will be used depending on the memory layout of the object.
  287. // Ref: http://www.x86-64.org/documentation/abi.pdf
  288. // Ref: http://www.agner.org/optimize/calling_conventions.pdf
  289. // If the application informs that the class should be treated as all integers, then we allow it
  290. if( !internal->hostReturnInMemory &&
  291. !(func->returnType.GetObjectType()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
  292. {
  293. engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
  294. asCString str;
  295. str.Format(TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL, func->returnType.Format(func->nameSpace).AddressOf());
  296. engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  297. engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
  298. }
  299. #endif
  300. }
  301. else if( objType & asOBJ_APP_PRIMITIVE )
  302. {
  303. internal->hostReturnInMemory = false;
  304. internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
  305. internal->hostReturnFloat = false;
  306. }
  307. else if( objType & asOBJ_APP_FLOAT )
  308. {
  309. internal->hostReturnInMemory = false;
  310. internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords();
  311. internal->hostReturnFloat = true;
  312. }
  313. }
  314. // Primitive types can easily be determined
  315. #ifdef HAS_128_BIT_PRIMITIVES
  316. else if( func->returnType.GetSizeInMemoryDWords() > 4 )
  317. {
  318. // Shouldn't be possible to get here
  319. asASSERT(false);
  320. }
  321. else if( func->returnType.GetSizeInMemoryDWords() == 4 )
  322. {
  323. internal->hostReturnInMemory = false;
  324. internal->hostReturnSize = 4;
  325. internal->hostReturnFloat = false;
  326. }
  327. #else
  328. else if( func->returnType.GetSizeInMemoryDWords() > 2 )
  329. {
  330. // Shouldn't be possible to get here
  331. asASSERT(false);
  332. }
  333. #endif
  334. else if( func->returnType.GetSizeInMemoryDWords() == 2 )
  335. {
  336. internal->hostReturnInMemory = false;
  337. internal->hostReturnSize = 2;
  338. internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttDouble, true));
  339. }
  340. else if( func->returnType.GetSizeInMemoryDWords() == 1 )
  341. {
  342. internal->hostReturnInMemory = false;
  343. internal->hostReturnSize = 1;
  344. internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttFloat, true));
  345. }
  346. else
  347. {
  348. internal->hostReturnInMemory = false;
  349. internal->hostReturnSize = 0;
  350. internal->hostReturnFloat = false;
  351. }
  352. // Calculate the size needed for the parameters
  353. internal->paramSize = func->GetSpaceNeededForArguments();
  354. // Verify if the function takes any objects by value
  355. asUINT n;
  356. internal->takesObjByVal = false;
  357. for( n = 0; n < func->parameterTypes.GetLength(); n++ )
  358. {
  359. if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() )
  360. {
  361. internal->takesObjByVal = true;
  362. // Can't pass objects by value unless the application type is informed
  363. if( !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) )
  364. {
  365. engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
  366. asCString str;
  367. str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf());
  368. engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  369. engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
  370. }
  371. #ifdef SPLIT_OBJS_BY_MEMBER_TYPES
  372. // It's not safe to pass objects by value because different registers
  373. // will be used depending on the memory layout of the object
  374. // Ref: http://www.x86-64.org/documentation/abi.pdf
  375. // Ref: http://www.agner.org/optimize/calling_conventions.pdf
  376. if(
  377. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  378. !(func->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) &&
  379. #endif
  380. #ifdef LARGE_OBJS_PASS_BY_REF
  381. func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE &&
  382. #endif
  383. !(func->parameterTypes[n].GetObjectType()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) )
  384. {
  385. engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf());
  386. asCString str;
  387. str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetObjectType()->name.AddressOf());
  388. engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
  389. engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0);
  390. }
  391. #endif
  392. break;
  393. }
  394. }
  395. // Prepare the clean up instructions for the function arguments
  396. internal->cleanArgs.SetLength(0);
  397. int offset = 0;
  398. for( n = 0; n < func->parameterTypes.GetLength(); n++ )
  399. {
  400. asCDataType &dt = func->parameterTypes[n];
  401. #if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF)
  402. bool needFree = false;
  403. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  404. if( dt.GetObjectType() && dt.GetObjectType()->flags & COMPLEX_MASK ) needFree = true;
  405. #endif
  406. #ifdef AS_LARGE_OBJS_PASSED_BY_REF
  407. if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true;
  408. #endif
  409. if( needFree &&
  410. dt.IsObject() &&
  411. !dt.IsObjectHandle() &&
  412. !dt.IsReference() )
  413. {
  414. asSSystemFunctionInterface::SClean clean;
  415. clean.op = 1; // call free
  416. clean.ot = dt.GetObjectType();
  417. clean.off = short(offset);
  418. #ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL
  419. // If the called function doesn't destroy objects passed by value we must do so here
  420. asSTypeBehaviour *beh = &dt.GetObjectType()->beh;
  421. if( beh->destruct )
  422. clean.op = 2; // call destruct, then free
  423. #endif
  424. internal->cleanArgs.PushLast(clean);
  425. }
  426. #endif
  427. if( n < internal->paramAutoHandles.GetLength() && internal->paramAutoHandles[n] )
  428. {
  429. asSSystemFunctionInterface::SClean clean;
  430. clean.op = 0; // call release
  431. clean.ot = dt.GetObjectType();
  432. clean.off = short(offset);
  433. internal->cleanArgs.PushLast(clean);
  434. }
  435. if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() )
  436. offset += AS_PTR_SIZE;
  437. else
  438. offset += dt.GetSizeOnStackDWords();
  439. }
  440. #endif // !defined(AS_MAX_PORTABILITY)
  441. return 0;
  442. }
  443. #ifdef AS_MAX_PORTABILITY
  444. int CallSystemFunction(int id, asCContext *context)
  445. {
  446. asCScriptEngine *engine = context->m_engine;
  447. asCScriptFunction *func = engine->scriptFunctions[id];
  448. asSSystemFunctionInterface *sysFunc = func->sysFuncIntf;
  449. int callConv = sysFunc->callConv;
  450. if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
  451. return context->CallGeneric(func);
  452. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  453. return 0;
  454. }
  455. #else
  456. //
  457. // CallSystemFunctionNative
  458. //
  459. // This function is implemented for each platform where the native calling conventions is supported.
  460. // See the various as_callfunc_xxx.cpp files for their implementation. It is responsible for preparing
  461. // the arguments for the function call, calling the function, and then retrieving the return value.
  462. //
  463. // Parameters:
  464. //
  465. // context - This is the context that can be used to retrieve specific information from the engine
  466. // descr - This is the script function object that holds the information on how to call the function
  467. // obj - This is the object pointer, if the call is for a class method, otherwise it is null
  468. // args - This is the function arguments, which are packed as in AngelScript
  469. // retPointer - This points to a the memory buffer where the return object is to be placed, if the function returns the value in memory rather than in registers
  470. // retQW2 - This output parameter should be used if the function returns a value larger than 64bits in registers
  471. // secondObj - This is the object pointer that the proxy method should invoke its method on when the call convention is THISCALL_OBJFIRST/LAST
  472. //
  473. // Return value:
  474. //
  475. // The function should return the value that is returned in registers.
  476. asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObj);
  477. int CallSystemFunction(int id, asCContext *context)
  478. {
  479. asCScriptEngine *engine = context->m_engine;
  480. asCScriptFunction *descr = engine->scriptFunctions[id];
  481. asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
  482. int callConv = sysFunc->callConv;
  483. if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
  484. return context->CallGeneric(descr);
  485. asQWORD retQW = 0;
  486. asQWORD retQW2 = 0;
  487. asDWORD *args = context->m_regs.stackPointer;
  488. void *retPointer = 0;
  489. int popSize = sysFunc->paramSize;
  490. #ifdef AS_NO_THISCALL_FUNCTOR_METHOD
  491. void *obj = 0;
  492. void *secondObj = 0;
  493. if( callConv >= ICC_THISCALL )
  494. {
  495. if( sysFunc->objForThiscall )
  496. {
  497. // This class method is being called as if it is a global function
  498. obj = sysFunc->objForThiscall;
  499. }
  500. else
  501. {
  502. // The object pointer should be popped from the context stack
  503. popSize += AS_PTR_SIZE;
  504. // Check for null pointer
  505. obj = (void*)*(asPWORD*)(args);
  506. if( obj == 0 )
  507. {
  508. context->SetInternalException(TXT_NULL_POINTER_ACCESS);
  509. return 0;
  510. }
  511. // Add the base offset for multiple inheritance
  512. #if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
  513. // On GNUC + ARM the lsb of the offset is used to indicate a virtual function
  514. // and the whole offset is thus shifted one bit left to keep the original
  515. // offset resolution
  516. // MIPS also work like ARM in this regard
  517. obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1));
  518. #else
  519. obj = (void*)(asPWORD(obj) + sysFunc->baseOffset);
  520. #endif
  521. // Skip the object pointer
  522. args += AS_PTR_SIZE;
  523. }
  524. }
  525. #else
  526. // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers
  527. // objForThiscall is the object pointer that should be used for the thiscall
  528. // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST
  529. // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST
  530. void *obj = 0;
  531. void *secondObj = 0;
  532. if( callConv >= ICC_THISCALL )
  533. {
  534. bool continueCheck = true; // True if need check objectPointer or context stack for object
  535. int continueCheckIndex = 0; // Index into objectsPtrs to save the object if continueCheck
  536. if( callConv >= ICC_THISCALL_OBJLAST )
  537. {
  538. asASSERT( sysFunc->objForThiscall != 0 );
  539. // This class method is being called as object method (sysFunc->objForThiscall must be set).
  540. obj = sysFunc->objForThiscall;
  541. continueCheckIndex = 1;
  542. }
  543. else if( sysFunc->objForThiscall )
  544. {
  545. // This class method is being called as if it is a global function
  546. obj = sysFunc->objForThiscall;
  547. continueCheck = false;
  548. }
  549. if( continueCheck )
  550. {
  551. void *tempPtr = 0;
  552. // The object pointer should be popped from the context stack
  553. popSize += AS_PTR_SIZE;
  554. // Check for null pointer
  555. tempPtr = (void*)*(asPWORD*)(args);
  556. if( tempPtr == 0 )
  557. {
  558. context->SetInternalException(TXT_NULL_POINTER_ACCESS);
  559. return 0;
  560. }
  561. // Add the base offset for multiple inheritance
  562. #if (defined(__GNUC__) && (defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA)
  563. // On GNUC + ARM the lsb of the offset is used to indicate a virtual function
  564. // and the whole offset is thus shifted one bit left to keep the original
  565. // offset resolution
  566. // MIPS also work like ARM in this regard
  567. tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1));
  568. #else
  569. tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset);
  570. #endif
  571. // Skip the object pointer
  572. args += AS_PTR_SIZE;
  573. if( continueCheckIndex )
  574. secondObj = tempPtr;
  575. else
  576. {
  577. asASSERT( obj == 0 );
  578. obj = tempPtr;
  579. }
  580. }
  581. }
  582. #endif // AS_NO_THISCALL_FUNCTOR_METHOD
  583. if( descr->DoesReturnOnStack() )
  584. {
  585. // Get the address of the location for the return value from the stack
  586. retPointer = (void*)*(asPWORD*)(args);
  587. popSize += AS_PTR_SIZE;
  588. args += AS_PTR_SIZE;
  589. // When returning the value on the location allocated by the called
  590. // we shouldn't set the object type in the register
  591. context->m_regs.objectType = 0;
  592. }
  593. else
  594. {
  595. // Set the object type of the reference held in the register
  596. context->m_regs.objectType = descr->returnType.GetObjectType();
  597. }
  598. context->m_callingSystemFunction = descr;
  599. bool cppException = false;
  600. #ifdef AS_NO_EXCEPTIONS
  601. retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj);
  602. #else
  603. // This try/catch block is to catch potential exception that may
  604. // be thrown by the registered function. The implementation of the
  605. // CallSystemFunctionNative() must make sure not to have any manual
  606. // clean-up after the call to the real function, or that won't be
  607. // executed in case of an exception.
  608. try
  609. {
  610. retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj);
  611. }
  612. catch(...)
  613. {
  614. cppException = true;
  615. // Convert the exception to a script exception so the VM can
  616. // properly report the error to the application and then clean up
  617. context->SetException(TXT_EXCEPTION_CAUGHT);
  618. }
  619. #endif
  620. context->m_callingSystemFunction = 0;
  621. // Store the returned value in our stack
  622. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  623. {
  624. if( descr->returnType.IsObjectHandle() )
  625. {
  626. #if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1
  627. // Since we're treating the system function as if it is returning a QWORD we are
  628. // actually receiving the value in the high DWORD of retQW.
  629. retQW >>= 32;
  630. #endif
  631. context->m_regs.objectRegister = (void*)(asPWORD)retQW;
  632. if( sysFunc->returnAutoHandle && context->m_regs.objectRegister )
  633. {
  634. asASSERT( !(descr->returnType.GetObjectType()->flags & asOBJ_NOCOUNT) );
  635. engine->CallObjectMethod(context->m_regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
  636. }
  637. }
  638. else
  639. {
  640. asASSERT( retPointer );
  641. if( !sysFunc->hostReturnInMemory )
  642. {
  643. // Copy the returned value to the pointer sent by the script engine
  644. if( sysFunc->hostReturnSize == 1 )
  645. {
  646. #if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1
  647. // Since we're treating the system function as if it is returning a QWORD we are
  648. // actually receiving the value in the high DWORD of retQW.
  649. retQW >>= 32;
  650. #endif
  651. *(asDWORD*)retPointer = (asDWORD)retQW;
  652. }
  653. else if( sysFunc->hostReturnSize == 2 )
  654. *(asQWORD*)retPointer = retQW;
  655. else if( sysFunc->hostReturnSize == 3 )
  656. {
  657. *(asQWORD*)retPointer = retQW;
  658. *(((asDWORD*)retPointer) + 2) = (asDWORD)retQW2;
  659. }
  660. else // if( sysFunc->hostReturnSize == 4 )
  661. {
  662. *(asQWORD*)retPointer = retQW;
  663. *(((asQWORD*)retPointer) + 1) = retQW2;
  664. }
  665. }
  666. if( context->m_status == asEXECUTION_EXCEPTION && !cppException )
  667. {
  668. // If the function raised a script exception it really shouldn't have
  669. // initialized the object. However, as it is a soft exception there is
  670. // no way for the application to not return a value, so instead we simply
  671. // destroy it here, to pretend it was never created.
  672. if( descr->returnType.GetObjectType()->beh.destruct )
  673. engine->CallObjectMethod(retPointer, descr->returnType.GetObjectType()->beh.destruct);
  674. }
  675. }
  676. }
  677. else
  678. {
  679. // Store value in value register
  680. if( sysFunc->hostReturnSize == 1 )
  681. {
  682. #if defined(AS_BIG_ENDIAN)
  683. // Since we're treating the system function as if it is returning a QWORD we are
  684. // actually receiving the value in the high DWORD of retQW.
  685. retQW >>= 32;
  686. // Due to endian issues we need to handle return values that are
  687. // less than a DWORD (32 bits) in size specially
  688. int numBytes = descr->returnType.GetSizeInMemoryBytes();
  689. if( descr->returnType.IsReference() ) numBytes = 4;
  690. switch( numBytes )
  691. {
  692. case 1:
  693. {
  694. // 8 bits
  695. asBYTE *val = (asBYTE*)&context->m_regs.valueRegister;
  696. val[0] = (asBYTE)retQW;
  697. val[1] = 0;
  698. val[2] = 0;
  699. val[3] = 0;
  700. val[4] = 0;
  701. val[5] = 0;
  702. val[6] = 0;
  703. val[7] = 0;
  704. }
  705. break;
  706. case 2:
  707. {
  708. // 16 bits
  709. asWORD *val = (asWORD*)&context->m_regs.valueRegister;
  710. val[0] = (asWORD)retQW;
  711. val[1] = 0;
  712. val[2] = 0;
  713. val[3] = 0;
  714. }
  715. break;
  716. default:
  717. {
  718. // 32 bits
  719. asDWORD *val = (asDWORD*)&context->m_regs.valueRegister;
  720. val[0] = (asDWORD)retQW;
  721. val[1] = 0;
  722. }
  723. break;
  724. }
  725. #else
  726. *(asDWORD*)&context->m_regs.valueRegister = (asDWORD)retQW;
  727. #endif
  728. }
  729. else
  730. context->m_regs.valueRegister = retQW;
  731. }
  732. // Clean up arguments
  733. const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
  734. if( cleanCount )
  735. {
  736. args = context->m_regs.stackPointer;
  737. // Skip the hidden argument for the return pointer
  738. // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
  739. if( descr->DoesReturnOnStack() )
  740. args += AS_PTR_SIZE;
  741. // Skip the object pointer on the stack
  742. // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction
  743. if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 )
  744. args += AS_PTR_SIZE;
  745. asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
  746. for( asUINT n = 0; n < cleanCount; n++, clean++ )
  747. {
  748. void **addr = (void**)&args[clean->off];
  749. if( clean->op == 0 )
  750. {
  751. if( *addr != 0 )
  752. {
  753. engine->CallObjectMethod(*addr, clean->ot->beh.release);
  754. *addr = 0;
  755. }
  756. }
  757. else
  758. {
  759. asASSERT( clean->op == 1 || clean->op == 2 );
  760. asASSERT( *addr );
  761. if( clean->op == 2 )
  762. engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
  763. engine->CallFree(*addr);
  764. }
  765. }
  766. }
  767. return popSize;
  768. }
  769. #endif // AS_MAX_PORTABILITY
  770. END_AS_NAMESPACE