as_scriptfunction.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2012 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_scriptfunction.cpp
  25. //
  26. // A container for a compiled script function
  27. //
  28. #include "as_config.h"
  29. #include "as_scriptfunction.h"
  30. #include "as_tokendef.h"
  31. #include "as_scriptengine.h"
  32. #include "as_callfunc.h"
  33. #include "as_bytecode.h"
  34. #include "as_texts.h"
  35. BEGIN_AS_NAMESPACE
  36. #ifdef AS_MAX_PORTABILITY
  37. static void ScriptFunction_AddRef_Generic(asIScriptGeneric *gen)
  38. {
  39. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  40. self->AddRef();
  41. }
  42. static void ScriptFunction_Release_Generic(asIScriptGeneric *gen)
  43. {
  44. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  45. self->Release();
  46. }
  47. static void ScriptFunction_GetRefCount_Generic(asIScriptGeneric *gen)
  48. {
  49. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  50. *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
  51. }
  52. static void ScriptFunction_SetFlag_Generic(asIScriptGeneric *gen)
  53. {
  54. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  55. self->SetFlag();
  56. }
  57. static void ScriptFunction_GetFlag_Generic(asIScriptGeneric *gen)
  58. {
  59. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  60. *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
  61. }
  62. static void ScriptFunction_EnumReferences_Generic(asIScriptGeneric *gen)
  63. {
  64. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  65. asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
  66. self->EnumReferences(engine);
  67. }
  68. static void ScriptFunction_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
  69. {
  70. asCScriptFunction *self = (asCScriptFunction*)gen->GetObject();
  71. asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
  72. self->ReleaseAllHandles(engine);
  73. }
  74. #endif
  75. void RegisterScriptFunction(asCScriptEngine *engine)
  76. {
  77. // Register the gc behaviours for the script functions
  78. int r = 0;
  79. UNUSED_VAR(r); // It is only used in debug mode
  80. engine->functionBehaviours.engine = engine;
  81. engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC | asOBJ_SCRIPT_FUNCTION;
  82. engine->functionBehaviours.name = "_builtin_function_";
  83. #ifndef AS_MAX_PORTABILITY
  84. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL); asASSERT( r >= 0 );
  85. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL); asASSERT( r >= 0 );
  86. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptFunction,GetRefCount), asCALL_THISCALL); asASSERT( r >= 0 );
  87. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptFunction,SetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
  88. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
  89. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL); asASSERT( r >= 0 );
  90. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL); asASSERT( r >= 0 );
  91. #else
  92. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  93. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  94. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptFunction_GetRefCount_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  95. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptFunction_SetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  96. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  97. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  98. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  99. #endif
  100. }
  101. // internal
  102. asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType)
  103. {
  104. refCount.set(1);
  105. this->engine = engine;
  106. funcType = _funcType;
  107. module = mod;
  108. objectType = 0;
  109. name = "";
  110. isReadOnly = false;
  111. isPrivate = false;
  112. isFinal = false;
  113. isOverride = false;
  114. stackNeeded = 0;
  115. sysFuncIntf = 0;
  116. signatureId = 0;
  117. scriptSectionIdx = -1;
  118. dontCleanUpOnException = false;
  119. vfTableIdx = -1;
  120. jitFunction = 0;
  121. gcFlag = false;
  122. userData = 0;
  123. id = 0;
  124. accessMask = 0xFFFFFFFF;
  125. isShared = false;
  126. variableSpace = 0;
  127. nameSpace = engine->nameSpaces[0];
  128. // Notify the GC of script functions
  129. if( funcType == asFUNC_SCRIPT && mod == 0 )
  130. engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
  131. }
  132. // internal
  133. asCScriptFunction::~asCScriptFunction()
  134. {
  135. // Imported functions are not reference counted, nor are dummy
  136. // functions that are allocated on the stack
  137. asASSERT( funcType == asFUNC_DUMMY ||
  138. funcType == asFUNC_IMPORTED ||
  139. refCount.get() == 0 );
  140. // If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do
  141. if( engine == 0 ) return;
  142. DestroyInternal();
  143. // Tell engine to free the function id. This will make it impossible to
  144. // refer to the function by id. Where this is done, it is quite possible
  145. // they will leak.
  146. if( funcType != -1 && funcType != asFUNC_IMPORTED && id )
  147. engine->FreeScriptFunctionId(id);
  148. id = 0;
  149. // Finally set the engine pointer to 0 because it must not be accessed again
  150. engine = 0;
  151. }
  152. // internal
  153. void asCScriptFunction::DestroyInternal()
  154. {
  155. // Clean up user data
  156. if( userData && engine->cleanFunctionFunc )
  157. engine->cleanFunctionFunc(this);
  158. userData = 0;
  159. // Release all references the function holds to other objects
  160. ReleaseReferences();
  161. parameterTypes.SetLength(0);
  162. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  163. byteCode.SetLength(0);
  164. for( asUINT n = 0; n < variables.GetLength(); n++ )
  165. asDELETE(variables[n],asSScriptVariable);
  166. variables.SetLength(0);
  167. for( asUINT p = 0; p < defaultArgs.GetLength(); p++ )
  168. if( defaultArgs[p] )
  169. asDELETE(defaultArgs[p], asCString);
  170. defaultArgs.SetLength(0);
  171. if( sysFuncIntf )
  172. asDELETE(sysFuncIntf,asSSystemFunctionInterface);
  173. sysFuncIntf = 0;
  174. }
  175. // interface
  176. int asCScriptFunction::GetId() const
  177. {
  178. return id;
  179. }
  180. // interface
  181. int asCScriptFunction::AddRef() const
  182. {
  183. gcFlag = false;
  184. asASSERT( funcType != asFUNC_IMPORTED );
  185. return refCount.atomicInc();
  186. }
  187. // interface
  188. int asCScriptFunction::Release() const
  189. {
  190. gcFlag = false;
  191. asASSERT( funcType != asFUNC_IMPORTED );
  192. int r = refCount.atomicDec();
  193. if( r == 0 && funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted
  194. asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
  195. return r;
  196. }
  197. // internal
  198. void asCScriptFunction::Orphan(asIScriptModule *mod)
  199. {
  200. if( mod && module == mod )
  201. {
  202. module = 0;
  203. if( funcType == asFUNC_SCRIPT && refCount.get() > 1 )
  204. {
  205. // This function is being orphaned, so notify the GC so it can check for circular references
  206. engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
  207. }
  208. }
  209. Release();
  210. }
  211. // interface
  212. int asCScriptFunction::GetTypeId() const
  213. {
  214. // This const cast is ok, the object won't be modified
  215. asCDataType dt = asCDataType::CreateFuncDef(const_cast<asCScriptFunction*>(this));
  216. return engine->GetTypeIdFromDataType(dt);
  217. }
  218. // interface
  219. bool asCScriptFunction::IsCompatibleWithTypeId(int typeId) const
  220. {
  221. asCDataType dt = engine->GetDataTypeFromTypeId(typeId);
  222. // Make sure the type is a function
  223. asCScriptFunction *func = dt.GetFuncDef();
  224. if( func == 0 )
  225. return false;
  226. if( !IsSignatureExceptNameEqual(func) )
  227. return false;
  228. // If this is a class method, then only return true if the object type is the same
  229. if( objectType != func->objectType )
  230. return false;
  231. return true;
  232. }
  233. // interface
  234. const char *asCScriptFunction::GetModuleName() const
  235. {
  236. if( module )
  237. {
  238. return module->name.AddressOf();
  239. }
  240. return 0;
  241. }
  242. // interface
  243. asIObjectType *asCScriptFunction::GetObjectType() const
  244. {
  245. return objectType;
  246. }
  247. // interface
  248. const char *asCScriptFunction::GetObjectName() const
  249. {
  250. if( objectType )
  251. return objectType->GetName();
  252. return 0;
  253. }
  254. // interface
  255. const char *asCScriptFunction::GetName() const
  256. {
  257. return name.AddressOf();
  258. }
  259. // interface
  260. const char *asCScriptFunction::GetNamespace() const
  261. {
  262. return nameSpace->name.AddressOf();
  263. }
  264. // interface
  265. bool asCScriptFunction::IsReadOnly() const
  266. {
  267. return isReadOnly;
  268. }
  269. // interface
  270. bool asCScriptFunction::IsPrivate() const
  271. {
  272. return isPrivate;
  273. }
  274. // internal
  275. int asCScriptFunction::GetSpaceNeededForArguments()
  276. {
  277. // We need to check the size for each type
  278. int s = 0;
  279. for( asUINT n = 0; n < parameterTypes.GetLength(); n++ )
  280. s += parameterTypes[n].GetSizeOnStackDWords();
  281. return s;
  282. }
  283. // internal
  284. int asCScriptFunction::GetSpaceNeededForReturnValue()
  285. {
  286. return returnType.GetSizeOnStackDWords();
  287. }
  288. // internal
  289. bool asCScriptFunction::DoesReturnOnStack() const
  290. {
  291. if( returnType.GetObjectType() &&
  292. (returnType.GetObjectType()->flags & asOBJ_VALUE) &&
  293. !returnType.IsReference() )
  294. return true;
  295. return false;
  296. }
  297. // internal
  298. asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace) const
  299. {
  300. asCString str;
  301. // TODO: default arg: Make the declaration with the default args an option
  302. // Don't add the return type for constructors and destructors
  303. if( !(returnType.GetTokenType() == ttVoid &&
  304. objectType &&
  305. (name == objectType->name || (name.GetLength() > 0 && name[0] == '~'))) )
  306. {
  307. str = returnType.Format();
  308. str += " ";
  309. }
  310. if( objectType && includeObjectName )
  311. {
  312. if( includeNamespace )
  313. str += objectType->nameSpace->name + "::";
  314. if( objectType->name != "" )
  315. str += objectType->name + "::";
  316. else
  317. str += "_unnamed_type_::";
  318. }
  319. else if( includeNamespace )
  320. {
  321. str += nameSpace->name + "::";
  322. }
  323. if( name == "" )
  324. str += "_unnamed_function_(";
  325. else
  326. str += name + "(";
  327. if( parameterTypes.GetLength() > 0 )
  328. {
  329. asUINT n;
  330. for( n = 0; n < parameterTypes.GetLength() - 1; n++ )
  331. {
  332. str += parameterTypes[n].Format();
  333. if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
  334. {
  335. if( inOutFlags[n] == asTM_INREF ) str += "in";
  336. else if( inOutFlags[n] == asTM_OUTREF ) str += "out";
  337. else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
  338. }
  339. if( defaultArgs.GetLength() > n && defaultArgs[n] )
  340. {
  341. asCString tmp;
  342. tmp.Format(" arg%d = %s", n, defaultArgs[n]->AddressOf());
  343. str += tmp;
  344. }
  345. str += ", ";
  346. }
  347. // Add the last parameter
  348. str += parameterTypes[n].Format();
  349. if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
  350. {
  351. if( inOutFlags[n] == asTM_INREF ) str += "in";
  352. else if( inOutFlags[n] == asTM_OUTREF ) str += "out";
  353. else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
  354. }
  355. if( defaultArgs.GetLength() > n && defaultArgs[n] )
  356. {
  357. asCString tmp;
  358. tmp.Format(" arg%d = %s", n, defaultArgs[n]->AddressOf());
  359. str += tmp;
  360. }
  361. }
  362. str += ")";
  363. if( isReadOnly )
  364. str += " const";
  365. return str;
  366. }
  367. // interface
  368. int asCScriptFunction::FindNextLineWithCode(int line) const
  369. {
  370. if( lineNumbers.GetLength() == 0 ) return -1;
  371. // Check if given line is outside function
  372. // TODO: should start at declaration instead of first line of code
  373. if( line < (lineNumbers[1]&0xFFFFF) ) return -1;
  374. if( line > (lineNumbers[lineNumbers.GetLength()-1]&0xFFFFF) ) return -1;
  375. // Find the line with code on or right after the input line
  376. // TODO: optimize: Do binary search instead
  377. if( line == (lineNumbers[1]&0xFFFFF) ) return line;
  378. for( asUINT n = 3; n < lineNumbers.GetLength(); n += 2 )
  379. {
  380. if( line <= (lineNumbers[n]&0xFFFFF) )
  381. return (lineNumbers[n]&0xFFFFF);
  382. }
  383. return -1;
  384. }
  385. // internal
  386. int asCScriptFunction::GetLineNumber(int programPosition, int *sectionIdx)
  387. {
  388. if( sectionIdx ) *sectionIdx = scriptSectionIdx;
  389. if( lineNumbers.GetLength() == 0 ) return 0;
  390. if( sectionIdx )
  391. {
  392. // Find the correct section index if the function is compiled from multiple sections
  393. // This array will be empty most of the time so we don't need a sofisticated algorithm to search it
  394. for( asUINT n = 0; n < sectionIdxs.GetLength(); n += 2 )
  395. {
  396. if( sectionIdxs[n] <= programPosition )
  397. *sectionIdx = sectionIdxs[n+1];
  398. }
  399. }
  400. // Do a binary search in the buffer
  401. int max = (int)lineNumbers.GetLength()/2 - 1;
  402. int min = 0;
  403. int i = max/2;
  404. for(;;)
  405. {
  406. if( lineNumbers[i*2] < programPosition )
  407. {
  408. // Have we found the largest number < programPosition?
  409. if( max == i ) return lineNumbers[i*2+1];
  410. if( lineNumbers[i*2+2] > programPosition ) return lineNumbers[i*2+1];
  411. min = i + 1;
  412. i = (max + min)/2;
  413. }
  414. else if( lineNumbers[i*2] > programPosition )
  415. {
  416. // Have we found the smallest number > programPosition?
  417. if( min == i ) return lineNumbers[i*2+1];
  418. max = i - 1;
  419. i = (max + min)/2;
  420. }
  421. else
  422. {
  423. // We found the exact position
  424. return lineNumbers[i*2+1];
  425. }
  426. }
  427. }
  428. // interface
  429. asEFuncType asCScriptFunction::GetFuncType() const
  430. {
  431. return funcType;
  432. }
  433. // interface
  434. asUINT asCScriptFunction::GetVarCount() const
  435. {
  436. return int(variables.GetLength());
  437. }
  438. // interface
  439. int asCScriptFunction::GetVar(asUINT index, const char **name, int *typeId) const
  440. {
  441. if( index >= variables.GetLength() )
  442. return asINVALID_ARG;
  443. if( name )
  444. *name = variables[index]->name.AddressOf();
  445. if( typeId )
  446. *typeId = engine->GetTypeIdFromDataType(variables[index]->type);
  447. return asSUCCESS;
  448. }
  449. // interface
  450. const char *asCScriptFunction::GetVarDecl(asUINT index) const
  451. {
  452. if( index >= variables.GetLength() )
  453. return 0;
  454. asCString *tempString = &asCThreadManager::GetLocalData()->string;
  455. *tempString = variables[index]->type.Format();
  456. *tempString += " " + variables[index]->name;
  457. return tempString->AddressOf();
  458. }
  459. // internal
  460. void asCScriptFunction::AddVariable(asCString &name, asCDataType &type, int stackOffset)
  461. {
  462. asSScriptVariable *var = asNEW(asSScriptVariable);
  463. if( var == 0 )
  464. {
  465. // Out of memory
  466. return;
  467. }
  468. var->name = name;
  469. var->type = type;
  470. var->stackOffset = stackOffset;
  471. var->declaredAtProgramPos = 0;
  472. variables.PushLast(var);
  473. }
  474. // internal
  475. void asCScriptFunction::ComputeSignatureId()
  476. {
  477. // This function will compute the signatureId based on the
  478. // function name, return type, and parameter types. The object
  479. // type for methods is not used, so that class methods and
  480. // interface methods match each other.
  481. for( asUINT n = 0; n < engine->signatureIds.GetLength(); n++ )
  482. {
  483. if( !IsSignatureEqual(engine->signatureIds[n]) ) continue;
  484. // We don't need to increment the reference counter here, because
  485. // asCScriptEngine::FreeScriptFunctionId will maintain the signature
  486. // id as the function is freed.
  487. signatureId = engine->signatureIds[n]->signatureId;
  488. return;
  489. }
  490. signatureId = id;
  491. engine->signatureIds.PushLast(this);
  492. }
  493. // internal
  494. bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const
  495. {
  496. if( !IsSignatureExceptNameEqual(func) || name != func->name ) return false;
  497. return true;
  498. }
  499. // internal
  500. bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const
  501. {
  502. return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly);
  503. }
  504. // internal
  505. bool asCScriptFunction::IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray<asCDataType> &paramTypes, const asCArray<asETypeModifiers> &paramInOut, const asCObjectType *objType, bool readOnly) const
  506. {
  507. if( this->returnType != retType ) return false;
  508. return IsSignatureExceptNameAndReturnTypeEqual(paramTypes, paramInOut, objType, readOnly);
  509. }
  510. // internal
  511. bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *func) const
  512. {
  513. return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->isReadOnly);
  514. }
  515. // internal
  516. bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray<asCDataType> &paramTypes, const asCArray<asETypeModifiers> &paramInOut, const asCObjectType *objType, bool readOnly) const
  517. {
  518. if( this->isReadOnly != readOnly ) return false;
  519. if( this->inOutFlags != paramInOut ) return false;
  520. if( this->parameterTypes != paramTypes ) return false;
  521. if( (this->objectType != 0) != (objType != 0) ) return false;
  522. return true;
  523. }
  524. // internal
  525. void asCScriptFunction::AddReferences()
  526. {
  527. asUINT n;
  528. // This array will be used to make sure we only add the reference to the same resource once
  529. // This is especially important for global variables, as it expects the initialization function
  530. // to hold only one reference to the variable. However, if the variable is initialized through
  531. // the default constructor followed by the assignment operator we will have two references to
  532. // the variable in the function.
  533. asCArray<void*> ptrs;
  534. // Only count references if there is any bytecode
  535. if( byteCode.GetLength() )
  536. {
  537. if( returnType.IsObject() )
  538. returnType.GetObjectType()->AddRef();
  539. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  540. if( parameterTypes[p].IsObject() )
  541. parameterTypes[p].GetObjectType()->AddRef();
  542. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  543. objVariableTypes[n]->AddRef();
  544. }
  545. // Go through the byte code and add references to all resources used by the function
  546. for( n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  547. {
  548. switch( *(asBYTE*)&byteCode[n] )
  549. {
  550. // Object types
  551. case asBC_OBJTYPE:
  552. case asBC_FREE:
  553. case asBC_REFCPY:
  554. case asBC_RefCpyV:
  555. {
  556. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  557. objType->AddRef();
  558. }
  559. break;
  560. // Object type and function
  561. case asBC_ALLOC:
  562. {
  563. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  564. objType->AddRef();
  565. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  566. if( func )
  567. engine->scriptFunctions[func]->AddRef();
  568. }
  569. break;
  570. // Global variables
  571. case asBC_PGA:
  572. case asBC_PshGPtr:
  573. case asBC_LDG:
  574. case asBC_PshG4:
  575. case asBC_LdGRdR4:
  576. case asBC_CpyGtoV4:
  577. case asBC_CpyVtoG4:
  578. case asBC_SetG4:
  579. // Need to increase the reference for each global variable
  580. {
  581. void *gvarPtr = (void*)asBC_PTRARG(&byteCode[n]);
  582. if( !gvarPtr ) break;
  583. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  584. if( !prop ) break;
  585. // Only addref the properties once
  586. if( !ptrs.Exists(gvarPtr) )
  587. {
  588. prop->AddRef();
  589. ptrs.PushLast(gvarPtr);
  590. }
  591. asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id);
  592. if( group != 0 ) group->AddRef();
  593. }
  594. break;
  595. // System functions
  596. case asBC_CALLSYS:
  597. {
  598. int funcId = asBC_INTARG(&byteCode[n]);
  599. asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId);
  600. if( group != 0 ) group->AddRef();
  601. engine->scriptFunctions[funcId]->AddRef();
  602. }
  603. break;
  604. // Functions
  605. case asBC_CALL:
  606. case asBC_CALLINTF:
  607. {
  608. int func = asBC_INTARG(&byteCode[n]);
  609. engine->scriptFunctions[func]->AddRef();
  610. }
  611. break;
  612. // Function pointers
  613. case asBC_FuncPtr:
  614. {
  615. asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&byteCode[n]);
  616. func->AddRef();
  617. }
  618. break;
  619. }
  620. }
  621. }
  622. // internal
  623. void asCScriptFunction::ReleaseReferences()
  624. {
  625. asUINT n;
  626. asCArray<void*> ptrs;
  627. // Only count references if there is any bytecode
  628. if( byteCode.GetLength() )
  629. {
  630. if( returnType.IsObject() )
  631. returnType.GetObjectType()->Release();
  632. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  633. if( parameterTypes[p].IsObject() )
  634. parameterTypes[p].GetObjectType()->Release();
  635. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  636. if( objVariableTypes[n] )
  637. objVariableTypes[n]->Release();
  638. }
  639. // Go through the byte code and release references to all resources used by the function
  640. for( n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  641. {
  642. switch( *(asBYTE*)&byteCode[n] )
  643. {
  644. // Object types
  645. case asBC_OBJTYPE:
  646. case asBC_FREE:
  647. case asBC_REFCPY:
  648. case asBC_RefCpyV:
  649. {
  650. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  651. if( objType )
  652. objType->Release();
  653. }
  654. break;
  655. // Object type and function
  656. case asBC_ALLOC:
  657. {
  658. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  659. if( objType )
  660. objType->Release();
  661. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  662. if( func )
  663. {
  664. asCScriptFunction *fptr = engine->scriptFunctions[func];
  665. if( fptr )
  666. fptr->Release();
  667. // The engine may have been forced to destroy the function internals early
  668. // and this may will make it impossible to find the function by id anymore.
  669. // This should only happen if the engine is released while the application
  670. // is still keeping functions alive.
  671. // TODO: Fix this possible memory leak
  672. }
  673. }
  674. break;
  675. // Global variables
  676. case asBC_PGA:
  677. case asBC_PshGPtr:
  678. case asBC_LDG:
  679. case asBC_PshG4:
  680. case asBC_LdGRdR4:
  681. case asBC_CpyGtoV4:
  682. case asBC_CpyVtoG4:
  683. case asBC_SetG4:
  684. // Need to increase the reference for each global variable
  685. {
  686. void *gvarPtr = (void*)asBC_PTRARG(&byteCode[n]);
  687. if( !gvarPtr ) break;
  688. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  689. if( !prop ) break;
  690. // Only release the properties once
  691. if( !ptrs.Exists(gvarPtr) )
  692. {
  693. prop->Release();
  694. ptrs.PushLast(gvarPtr);
  695. }
  696. asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id);
  697. if( group != 0 ) group->Release();
  698. }
  699. break;
  700. // System functions
  701. case asBC_CALLSYS:
  702. {
  703. int funcId = asBC_INTARG(&byteCode[n]);
  704. asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId);
  705. if( group != 0 ) group->Release();
  706. if( funcId )
  707. engine->scriptFunctions[funcId]->Release();
  708. }
  709. break;
  710. // Functions
  711. case asBC_CALL:
  712. case asBC_CALLINTF:
  713. {
  714. int func = asBC_INTARG(&byteCode[n]);
  715. if( func )
  716. {
  717. asCScriptFunction *fptr = engine->scriptFunctions[func];
  718. if( fptr )
  719. fptr->Release();
  720. // The engine may have been forced to destroy the function internals early
  721. // and this may will make it impossible to find the function by id anymore.
  722. // This should only happen if the engine is released while the application
  723. // is still keeping functions alive.
  724. // TODO: Fix this possible memory leak
  725. }
  726. }
  727. break;
  728. // Function pointers
  729. case asBC_FuncPtr:
  730. {
  731. asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&byteCode[n]);
  732. if( func )
  733. func->Release();
  734. }
  735. break;
  736. }
  737. }
  738. // Release the jit compiled function
  739. if( jitFunction )
  740. engine->jitCompiler->ReleaseJITFunction(jitFunction);
  741. jitFunction = 0;
  742. }
  743. // interface
  744. int asCScriptFunction::GetReturnTypeId() const
  745. {
  746. return engine->GetTypeIdFromDataType(returnType);
  747. }
  748. // interface
  749. asUINT asCScriptFunction::GetParamCount() const
  750. {
  751. return (asUINT)parameterTypes.GetLength();
  752. }
  753. // interface
  754. int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
  755. {
  756. if( index >= parameterTypes.GetLength() )
  757. return asINVALID_ARG;
  758. if( flags )
  759. *flags = inOutFlags[index];
  760. return engine->GetTypeIdFromDataType(parameterTypes[index]);
  761. }
  762. // interface
  763. asIScriptEngine *asCScriptFunction::GetEngine() const
  764. {
  765. return engine;
  766. }
  767. // interface
  768. const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace) const
  769. {
  770. asCString *tempString = &asCThreadManager::GetLocalData()->string;
  771. *tempString = GetDeclarationStr(includeObjectName, includeNamespace);
  772. return tempString->AddressOf();
  773. }
  774. // interface
  775. const char *asCScriptFunction::GetScriptSectionName() const
  776. {
  777. if( scriptSectionIdx >= 0 )
  778. return engine->scriptSectionNames[scriptSectionIdx]->AddressOf();
  779. return 0;
  780. }
  781. // interface
  782. const char *asCScriptFunction::GetConfigGroup() const
  783. {
  784. asCConfigGroup *group = 0;
  785. if( funcType != asFUNC_FUNCDEF )
  786. group = engine->FindConfigGroupForFunction(id);
  787. else
  788. group = engine->FindConfigGroupForFuncDef(this);
  789. if( group == 0 )
  790. return 0;
  791. return group->groupName.AddressOf();
  792. }
  793. // interface
  794. asDWORD asCScriptFunction::GetAccessMask() const
  795. {
  796. return accessMask;
  797. }
  798. // internal
  799. void asCScriptFunction::JITCompile()
  800. {
  801. asIJITCompiler *jit = engine->GetJITCompiler();
  802. if( !jit )
  803. return;
  804. // Release the previous function, if any
  805. if( jitFunction )
  806. {
  807. engine->jitCompiler->ReleaseJITFunction(jitFunction);
  808. jitFunction = 0;
  809. }
  810. // Compile for native system
  811. int r = jit->CompileFunction(this, &jitFunction);
  812. if( r < 0 )
  813. {
  814. asASSERT( jitFunction == 0 );
  815. }
  816. }
  817. // interface
  818. asDWORD *asCScriptFunction::GetByteCode(asUINT *length)
  819. {
  820. if( length )
  821. *length = (asUINT)byteCode.GetLength();
  822. if( byteCode.GetLength() )
  823. {
  824. return byteCode.AddressOf();
  825. }
  826. return 0;
  827. }
  828. // interface
  829. void *asCScriptFunction::SetUserData(void *data)
  830. {
  831. void *oldData = userData;
  832. userData = data;
  833. return oldData;
  834. }
  835. // interface
  836. void *asCScriptFunction::GetUserData() const
  837. {
  838. return userData;
  839. }
  840. // internal
  841. // TODO: cleanup: This method should probably be a member of the engine
  842. asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr)
  843. {
  844. asSMapNode<void*, asCGlobalProperty*> *node;
  845. if( engine->varAddressMap.MoveTo(&node, gvarPtr) )
  846. {
  847. asASSERT(gvarPtr == node->value->GetAddressOfValue());
  848. return node->value;
  849. }
  850. return 0;
  851. }
  852. // internal
  853. int asCScriptFunction::GetRefCount()
  854. {
  855. return refCount.get();
  856. }
  857. // internal
  858. void asCScriptFunction::SetFlag()
  859. {
  860. gcFlag = true;
  861. }
  862. // internal
  863. bool asCScriptFunction::GetFlag()
  864. {
  865. return gcFlag;
  866. }
  867. // internal
  868. void asCScriptFunction::EnumReferences(asIScriptEngine *)
  869. {
  870. // Notify the GC of all object types used
  871. if( returnType.IsObject() )
  872. engine->GCEnumCallback(returnType.GetObjectType());
  873. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  874. if( parameterTypes[p].IsObject() )
  875. engine->GCEnumCallback(parameterTypes[p].GetObjectType());
  876. for( asUINT t = 0; t < objVariableTypes.GetLength(); t++ )
  877. engine->GCEnumCallback(objVariableTypes[t]);
  878. // Notify the GC of all script functions that is accessed
  879. for( asUINT n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  880. {
  881. switch( *(asBYTE*)&byteCode[n] )
  882. {
  883. case asBC_OBJTYPE:
  884. case asBC_FREE:
  885. case asBC_REFCPY:
  886. case asBC_RefCpyV:
  887. {
  888. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  889. engine->GCEnumCallback(objType);
  890. }
  891. break;
  892. case asBC_ALLOC:
  893. {
  894. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  895. engine->GCEnumCallback(objType);
  896. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  897. if( func )
  898. engine->GCEnumCallback(engine->scriptFunctions[func]);
  899. }
  900. break;
  901. case asBC_CALL:
  902. case asBC_CALLINTF:
  903. {
  904. int func = asBC_INTARG(&byteCode[n]);
  905. if( func )
  906. engine->GCEnumCallback(engine->scriptFunctions[func]);
  907. }
  908. break;
  909. // Function pointers
  910. case asBC_FuncPtr:
  911. {
  912. asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&byteCode[n]);
  913. if( func )
  914. engine->GCEnumCallback(func);
  915. }
  916. break;
  917. // Global variables
  918. case asBC_PGA:
  919. case asBC_PshGPtr:
  920. case asBC_LDG:
  921. case asBC_PshG4:
  922. case asBC_LdGRdR4:
  923. case asBC_CpyGtoV4:
  924. case asBC_CpyVtoG4:
  925. case asBC_SetG4:
  926. // Need to enumerate the reference for each global variable
  927. {
  928. // TODO: optimize: Keep an array of accessed global properties
  929. void *gvarPtr = (void*)asBC_PTRARG(&byteCode[n]);
  930. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  931. engine->GCEnumCallback(prop);
  932. }
  933. break;
  934. }
  935. }
  936. }
  937. // internal
  938. void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
  939. {
  940. // Release paramaters
  941. if( byteCode.GetLength() )
  942. {
  943. if( returnType.IsObject() )
  944. {
  945. returnType.GetObjectType()->Release();
  946. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  947. }
  948. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  949. if( parameterTypes[p].IsObject() )
  950. {
  951. parameterTypes[p].GetObjectType()->Release();
  952. parameterTypes[p] = asCDataType::CreatePrimitive(ttInt, false);
  953. }
  954. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  955. objVariableTypes[n]->Release();
  956. objVariableTypes.SetLength(0);
  957. }
  958. // Release all script functions
  959. for( asUINT n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  960. {
  961. switch( *(asBYTE*)&byteCode[n] )
  962. {
  963. // Object types
  964. case asBC_OBJTYPE:
  965. case asBC_FREE:
  966. case asBC_REFCPY:
  967. case asBC_RefCpyV:
  968. {
  969. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  970. if( objType )
  971. {
  972. objType->Release();
  973. *(void**)&byteCode[n+1] = 0;
  974. }
  975. }
  976. break;
  977. case asBC_ALLOC:
  978. {
  979. asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
  980. if( objType )
  981. {
  982. objType->Release();
  983. * (void**)&byteCode[n+1] = 0;
  984. }
  985. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  986. if( func )
  987. {
  988. engine->scriptFunctions[func]->Release();
  989. byteCode[n+AS_PTR_SIZE+1] = 0;
  990. }
  991. }
  992. break;
  993. case asBC_CALL:
  994. case asBC_CALLINTF:
  995. {
  996. int func = asBC_INTARG(&byteCode[n]);
  997. if( func )
  998. {
  999. engine->scriptFunctions[func]->Release();
  1000. byteCode[n+1] = 0;
  1001. }
  1002. }
  1003. break;
  1004. // Function pointers
  1005. case asBC_FuncPtr:
  1006. {
  1007. asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&byteCode[n]);
  1008. if( func )
  1009. {
  1010. func->Release();
  1011. *(asPWORD*)&byteCode[n+1] = 0;
  1012. }
  1013. }
  1014. break;
  1015. // The global variables are not released here. It is enough that the global
  1016. // variable itself release the function to break the circle
  1017. }
  1018. }
  1019. }
  1020. // internal
  1021. bool asCScriptFunction::IsShared() const
  1022. {
  1023. // All system functions are shared
  1024. if( funcType == asFUNC_SYSTEM ) return true;
  1025. // All class methods for shared classes are also shared
  1026. if( objectType && (objectType->flags & asOBJ_SHARED) ) return true;
  1027. // Functions that have been specifically marked as shared are shared
  1028. return isShared;
  1029. }
  1030. // internal
  1031. bool asCScriptFunction::IsFinal() const
  1032. {
  1033. return isFinal;
  1034. }
  1035. // internal
  1036. bool asCScriptFunction::IsOverride() const
  1037. {
  1038. return isOverride;
  1039. }
  1040. END_AS_NAMESPACE