as_scriptfunction.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2011 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;
  79. engine->functionBehaviours.engine = engine;
  80. engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC;
  81. engine->functionBehaviours.name = "_builtin_function_";
  82. #ifndef AS_MAX_PORTABILITY
  83. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL); asASSERT( r >= 0 );
  84. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL); asASSERT( r >= 0 );
  85. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptFunction,GetRefCount), asCALL_THISCALL); asASSERT( r >= 0 );
  86. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptFunction,SetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
  87. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL); asASSERT( r >= 0 );
  88. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL); asASSERT( r >= 0 );
  89. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL); asASSERT( r >= 0 );
  90. #else
  91. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  92. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  93. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptFunction_GetRefCount_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  94. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptFunction_SetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  95. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  96. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  97. r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC); asASSERT( r >= 0 );
  98. #endif
  99. }
  100. // internal
  101. asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType)
  102. {
  103. refCount.set(1);
  104. this->engine = engine;
  105. funcType = _funcType;
  106. module = mod;
  107. objectType = 0;
  108. name = "";
  109. isReadOnly = false;
  110. isPrivate = false;
  111. stackNeeded = 0;
  112. sysFuncIntf = 0;
  113. signatureId = 0;
  114. scriptSectionIdx = -1;
  115. dontCleanUpOnException = false;
  116. vfTableIdx = -1;
  117. jitFunction = 0;
  118. gcFlag = false;
  119. userData = 0;
  120. id = 0;
  121. accessMask = 0xFFFFFFFF;
  122. isShared = false;
  123. // TODO: optimize: The engine could notify the GC just before it wants to
  124. // discard the function. That way the GC won't waste time
  125. // trying to determine if the functions are garbage before
  126. // they can actually be considered garbage.
  127. // Notify the GC of script functions
  128. if( funcType == asFUNC_SCRIPT )
  129. engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
  130. }
  131. // internal
  132. asCScriptFunction::~asCScriptFunction()
  133. {
  134. // Clean user data
  135. if( userData && engine->cleanFunctionFunc )
  136. engine->cleanFunctionFunc(this);
  137. // Imported functions are not reference counted, nor are dummy
  138. // functions that are allocated on the stack
  139. asASSERT( funcType == asFUNC_DUMMY ||
  140. funcType == asFUNC_IMPORTED ||
  141. refCount.get() == 0 );
  142. ReleaseReferences();
  143. // Tell engine to free the function id
  144. if( funcType != -1 && funcType != asFUNC_IMPORTED && id )
  145. engine->FreeScriptFunctionId(id);
  146. for( asUINT n = 0; n < variables.GetLength(); n++ )
  147. {
  148. asDELETE(variables[n],asSScriptVariable);
  149. }
  150. if( sysFuncIntf )
  151. {
  152. asDELETE(sysFuncIntf,asSSystemFunctionInterface);
  153. }
  154. for( asUINT p = 0; p < defaultArgs.GetLength(); p++ )
  155. {
  156. if( defaultArgs[p] )
  157. asDELETE(defaultArgs[p], asCString);
  158. }
  159. }
  160. // interface
  161. int asCScriptFunction::GetId() const
  162. {
  163. return id;
  164. }
  165. // interface
  166. int asCScriptFunction::AddRef() const
  167. {
  168. gcFlag = false;
  169. asASSERT( funcType != asFUNC_IMPORTED );
  170. return refCount.atomicInc();
  171. }
  172. // interface
  173. int asCScriptFunction::Release() const
  174. {
  175. gcFlag = false;
  176. asASSERT( funcType != asFUNC_IMPORTED );
  177. int r = refCount.atomicDec();
  178. if( r == 0 && funcType != -1 ) // Dummy functions are allocated on the stack and cannot be deleted
  179. asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction);
  180. return r;
  181. }
  182. // interface
  183. const char *asCScriptFunction::GetModuleName() const
  184. {
  185. if( module )
  186. {
  187. return module->name.AddressOf();
  188. }
  189. return 0;
  190. }
  191. // interface
  192. asIObjectType *asCScriptFunction::GetObjectType() const
  193. {
  194. return objectType;
  195. }
  196. // interface
  197. const char *asCScriptFunction::GetObjectName() const
  198. {
  199. if( objectType )
  200. return objectType->GetName();
  201. return 0;
  202. }
  203. // interface
  204. const char *asCScriptFunction::GetName() const
  205. {
  206. return name.AddressOf();
  207. }
  208. // interface
  209. bool asCScriptFunction::IsReadOnly() const
  210. {
  211. return isReadOnly;
  212. }
  213. // interface
  214. bool asCScriptFunction::IsPrivate() const
  215. {
  216. return isPrivate;
  217. }
  218. // internal
  219. int asCScriptFunction::GetSpaceNeededForArguments()
  220. {
  221. // We need to check the size for each type
  222. int s = 0;
  223. for( asUINT n = 0; n < parameterTypes.GetLength(); n++ )
  224. s += parameterTypes[n].GetSizeOnStackDWords();
  225. return s;
  226. }
  227. // internal
  228. int asCScriptFunction::GetSpaceNeededForReturnValue()
  229. {
  230. return returnType.GetSizeOnStackDWords();
  231. }
  232. // internal
  233. bool asCScriptFunction::DoesReturnOnStack() const
  234. {
  235. if( returnType.GetObjectType() &&
  236. (returnType.GetObjectType()->flags & asOBJ_VALUE) &&
  237. !returnType.IsReference() )
  238. return true;
  239. return false;
  240. }
  241. // internal
  242. asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName) const
  243. {
  244. asCString str;
  245. // TODO: default arg: Make the declaration with the default args an option
  246. // Don't add the return type for constructors and destructors
  247. if( !(returnType.GetTokenType() == ttVoid &&
  248. objectType &&
  249. (name == objectType->name || (name.GetLength() > 0 && name[0] == '~'))) )
  250. {
  251. str = returnType.Format();
  252. str += " ";
  253. }
  254. if( objectType && includeObjectName )
  255. {
  256. if( objectType->name != "" )
  257. str += objectType->name + "::";
  258. else
  259. str += "_unnamed_type_::";
  260. }
  261. if( name == "" )
  262. str += "_unnamed_function_(";
  263. else
  264. str += name + "(";
  265. if( parameterTypes.GetLength() > 0 )
  266. {
  267. asUINT n;
  268. for( n = 0; n < parameterTypes.GetLength() - 1; n++ )
  269. {
  270. str += parameterTypes[n].Format();
  271. if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
  272. {
  273. if( inOutFlags[n] == asTM_INREF ) str += "in";
  274. else if( inOutFlags[n] == asTM_OUTREF ) str += "out";
  275. else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
  276. }
  277. if( defaultArgs.GetLength() > n && defaultArgs[n] )
  278. {
  279. asCString tmp;
  280. tmp.Format(" arg%d = %s", n, defaultArgs[n]->AddressOf());
  281. str += tmp;
  282. }
  283. str += ", ";
  284. }
  285. // Add the last parameter
  286. str += parameterTypes[n].Format();
  287. if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n )
  288. {
  289. if( inOutFlags[n] == asTM_INREF ) str += "in";
  290. else if( inOutFlags[n] == asTM_OUTREF ) str += "out";
  291. else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout";
  292. }
  293. if( defaultArgs.GetLength() > n && defaultArgs[n] )
  294. {
  295. asCString tmp;
  296. tmp.Format(" arg%d = %s", n, defaultArgs[n]->AddressOf());
  297. str += tmp;
  298. }
  299. }
  300. str += ")";
  301. if( isReadOnly )
  302. str += " const";
  303. return str;
  304. }
  305. // interface
  306. int asCScriptFunction::FindNextLineWithCode(int line) const
  307. {
  308. if( lineNumbers.GetLength() == 0 ) return -1;
  309. // Check if given line is outside function
  310. // TODO: should start at declaration instead of first line of code
  311. if( line < (lineNumbers[1]&0xFFFFF) ) return -1;
  312. if( line > (lineNumbers[lineNumbers.GetLength()-1]&0xFFFFF) ) return -1;
  313. // Find the line with code on or right after the input line
  314. // TODO: optimize: Do binary search instead
  315. if( line == (lineNumbers[1]&0xFFFFF) ) return line;
  316. for( asUINT n = 3; n < lineNumbers.GetLength(); n += 2 )
  317. {
  318. if( line <= (lineNumbers[n]&0xFFFFF) )
  319. return (lineNumbers[n]&0xFFFFF);
  320. }
  321. return -1;
  322. }
  323. // internal
  324. int asCScriptFunction::GetLineNumber(int programPosition)
  325. {
  326. if( lineNumbers.GetLength() == 0 ) return 0;
  327. // Do a binary search in the buffer
  328. int max = (int)lineNumbers.GetLength()/2 - 1;
  329. int min = 0;
  330. int i = max/2;
  331. for(;;)
  332. {
  333. if( lineNumbers[i*2] < programPosition )
  334. {
  335. // Have we found the largest number < programPosition?
  336. if( max == i ) return lineNumbers[i*2+1];
  337. if( lineNumbers[i*2+2] > programPosition ) return lineNumbers[i*2+1];
  338. min = i + 1;
  339. i = (max + min)/2;
  340. }
  341. else if( lineNumbers[i*2] > programPosition )
  342. {
  343. // Have we found the smallest number > programPosition?
  344. if( min == i ) return lineNumbers[i*2+1];
  345. max = i - 1;
  346. i = (max + min)/2;
  347. }
  348. else
  349. {
  350. // We found the exact position
  351. return lineNumbers[i*2+1];
  352. }
  353. }
  354. }
  355. // interface
  356. asEFuncType asCScriptFunction::GetFuncType() const
  357. {
  358. return funcType;
  359. }
  360. // interface
  361. asUINT asCScriptFunction::GetVarCount() const
  362. {
  363. return int(variables.GetLength());
  364. }
  365. // interface
  366. int asCScriptFunction::GetVar(asUINT index, const char **name, int *typeId) const
  367. {
  368. if( index >= variables.GetLength() )
  369. return asINVALID_ARG;
  370. if( name )
  371. *name = variables[index]->name.AddressOf();
  372. if( typeId )
  373. *typeId = engine->GetTypeIdFromDataType(variables[index]->type);
  374. return asSUCCESS;
  375. }
  376. // interface
  377. const char *asCScriptFunction::GetVarDecl(asUINT index) const
  378. {
  379. if( index >= variables.GetLength() )
  380. return 0;
  381. asASSERT(threadManager);
  382. asCString *tempString = &threadManager->GetLocalData()->string;
  383. *tempString = variables[index]->type.Format();
  384. *tempString += " " + variables[index]->name;
  385. return tempString->AddressOf();
  386. }
  387. // internal
  388. void asCScriptFunction::AddVariable(asCString &name, asCDataType &type, int stackOffset)
  389. {
  390. asSScriptVariable *var = asNEW(asSScriptVariable);
  391. var->name = name;
  392. var->type = type;
  393. var->stackOffset = stackOffset;
  394. var->declaredAtProgramPos = 0;
  395. variables.PushLast(var);
  396. }
  397. // internal
  398. void asCScriptFunction::ComputeSignatureId()
  399. {
  400. // This function will compute the signatureId based on the
  401. // function name, return type, and parameter types. The object
  402. // type for methods is not used, so that class methods and
  403. // interface methods match each other.
  404. for( asUINT n = 0; n < engine->signatureIds.GetLength(); n++ )
  405. {
  406. if( !IsSignatureEqual(engine->signatureIds[n]) ) continue;
  407. // We don't need to increment the reference counter here, because
  408. // asCScriptEngine::FreeScriptFunctionId will maintain the signature
  409. // id as the function is freed.
  410. signatureId = engine->signatureIds[n]->signatureId;
  411. return;
  412. }
  413. signatureId = id;
  414. engine->signatureIds.PushLast(this);
  415. }
  416. // internal
  417. bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const
  418. {
  419. if( !IsSignatureExceptNameEqual(func) || name != func->name ) return false;
  420. return true;
  421. }
  422. // internal
  423. bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const
  424. {
  425. if( returnType != func->returnType ) return false;
  426. if( isReadOnly != func->isReadOnly ) return false;
  427. if( inOutFlags != func->inOutFlags ) return false;
  428. if( parameterTypes != func->parameterTypes ) return false;
  429. if( (objectType != 0) != (func->objectType != 0) ) return false;
  430. return true;
  431. }
  432. // internal
  433. void asCScriptFunction::AddReferences()
  434. {
  435. asUINT n;
  436. // This array will be used to make sure we only add the reference to the same resource once
  437. // This is especially important for global variables, as it expects the initialization function
  438. // to hold only one reference to the variable. However, if the variable is initialized through
  439. // the default constructor followed by the assignment operator we will have two references to
  440. // the variable in the function.
  441. asCArray<void*> ptrs;
  442. // Only count references if there is any bytecode
  443. if( byteCode.GetLength() )
  444. {
  445. if( returnType.IsObject() )
  446. returnType.GetObjectType()->AddRef();
  447. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  448. if( parameterTypes[p].IsObject() )
  449. parameterTypes[p].GetObjectType()->AddRef();
  450. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  451. objVariableTypes[n]->AddRef();
  452. }
  453. // Go through the byte code and add references to all resources used by the function
  454. for( n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  455. {
  456. switch( *(asBYTE*)&byteCode[n] )
  457. {
  458. // Object types
  459. case asBC_OBJTYPE:
  460. case asBC_FREE:
  461. case asBC_REFCPY:
  462. {
  463. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  464. objType->AddRef();
  465. }
  466. break;
  467. // Object type and function
  468. case asBC_ALLOC:
  469. {
  470. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  471. objType->AddRef();
  472. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  473. if( func )
  474. engine->scriptFunctions[func]->AddRef();
  475. }
  476. break;
  477. // Global variables
  478. case asBC_PGA:
  479. case asBC_LDG:
  480. case asBC_PshG4:
  481. case asBC_LdGRdR4:
  482. case asBC_CpyGtoV4:
  483. case asBC_CpyVtoG4:
  484. case asBC_SetG4:
  485. // Need to increase the reference for each global variable
  486. {
  487. void *gvarPtr = (void*)(size_t)asBC_PTRARG(&byteCode[n]);
  488. if( !gvarPtr ) break;
  489. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  490. if( !prop ) break;
  491. // Only addref the properties once
  492. if( !ptrs.Exists(gvarPtr) )
  493. {
  494. prop->AddRef();
  495. ptrs.PushLast(gvarPtr);
  496. }
  497. asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id);
  498. if( group != 0 ) group->AddRef();
  499. }
  500. break;
  501. // System functions
  502. case asBC_CALLSYS:
  503. {
  504. int funcId = asBC_INTARG(&byteCode[n]);
  505. asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId);
  506. if( group != 0 ) group->AddRef();
  507. engine->scriptFunctions[funcId]->AddRef();
  508. }
  509. break;
  510. // Functions
  511. case asBC_CALL:
  512. case asBC_CALLINTF:
  513. {
  514. int func = asBC_INTARG(&byteCode[n]);
  515. engine->scriptFunctions[func]->AddRef();
  516. }
  517. break;
  518. // Function pointers
  519. case asBC_FuncPtr:
  520. {
  521. asCScriptFunction *func = (asCScriptFunction*)(size_t)asBC_PTRARG(&byteCode[n]);
  522. func->AddRef();
  523. }
  524. break;
  525. }
  526. }
  527. }
  528. // internal
  529. void asCScriptFunction::ReleaseReferences()
  530. {
  531. asUINT n;
  532. asCArray<void*> ptrs;
  533. // Only count references if there is any bytecode
  534. if( byteCode.GetLength() )
  535. {
  536. if( returnType.IsObject() )
  537. returnType.GetObjectType()->Release();
  538. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  539. if( parameterTypes[p].IsObject() )
  540. parameterTypes[p].GetObjectType()->Release();
  541. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  542. if( objVariableTypes[n] )
  543. objVariableTypes[n]->Release();
  544. }
  545. // Go through the byte code and release 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. {
  555. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  556. if( objType )
  557. objType->Release();
  558. }
  559. break;
  560. // Object type and function
  561. case asBC_ALLOC:
  562. {
  563. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  564. if( objType )
  565. objType->Release();
  566. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  567. if( func )
  568. engine->scriptFunctions[func]->Release();
  569. }
  570. break;
  571. // Global variables
  572. case asBC_PGA:
  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*)(size_t)asBC_PTRARG(&byteCode[n]);
  582. if( !gvarPtr ) break;
  583. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  584. if( !prop ) break;
  585. // Only release the properties once
  586. if( !ptrs.Exists(gvarPtr) )
  587. {
  588. prop->Release();
  589. ptrs.PushLast(gvarPtr);
  590. }
  591. asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id);
  592. if( group != 0 ) group->Release();
  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->Release();
  601. if( funcId )
  602. engine->scriptFunctions[funcId]->Release();
  603. }
  604. break;
  605. // Functions
  606. case asBC_CALL:
  607. case asBC_CALLINTF:
  608. {
  609. int func = asBC_INTARG(&byteCode[n]);
  610. if( func )
  611. engine->scriptFunctions[func]->Release();
  612. }
  613. break;
  614. // Function pointers
  615. case asBC_FuncPtr:
  616. {
  617. asCScriptFunction *func = (asCScriptFunction*)(size_t)asBC_PTRARG(&byteCode[n]);
  618. if( func )
  619. func->Release();
  620. }
  621. break;
  622. }
  623. }
  624. // Release the jit compiled function
  625. if( jitFunction )
  626. engine->jitCompiler->ReleaseJITFunction(jitFunction);
  627. jitFunction = 0;
  628. }
  629. // interface
  630. int asCScriptFunction::GetReturnTypeId() const
  631. {
  632. return engine->GetTypeIdFromDataType(returnType);
  633. }
  634. // interface
  635. asUINT asCScriptFunction::GetParamCount() const
  636. {
  637. return (asUINT)parameterTypes.GetLength();
  638. }
  639. // interface
  640. int asCScriptFunction::GetParamTypeId(asUINT index, asDWORD *flags) const
  641. {
  642. if( index >= parameterTypes.GetLength() )
  643. return asINVALID_ARG;
  644. if( flags )
  645. *flags = inOutFlags[index];
  646. return engine->GetTypeIdFromDataType(parameterTypes[index]);
  647. }
  648. // interface
  649. asIScriptEngine *asCScriptFunction::GetEngine() const
  650. {
  651. return engine;
  652. }
  653. // interface
  654. const char *asCScriptFunction::GetDeclaration(bool includeObjectName) const
  655. {
  656. asASSERT(threadManager);
  657. asCString *tempString = &threadManager->GetLocalData()->string;
  658. *tempString = GetDeclarationStr(includeObjectName);
  659. return tempString->AddressOf();
  660. }
  661. // interface
  662. const char *asCScriptFunction::GetScriptSectionName() const
  663. {
  664. if( scriptSectionIdx >= 0 )
  665. return engine->scriptSectionNames[scriptSectionIdx]->AddressOf();
  666. return 0;
  667. }
  668. // interface
  669. const char *asCScriptFunction::GetConfigGroup() const
  670. {
  671. asCConfigGroup *group = engine->FindConfigGroupForFunction(id);
  672. if( group == 0 )
  673. return 0;
  674. return group->groupName.AddressOf();
  675. }
  676. // internal
  677. void asCScriptFunction::JITCompile()
  678. {
  679. asIJITCompiler *jit = engine->GetJITCompiler();
  680. if( !jit )
  681. return;
  682. // Release the previous function, if any
  683. if( jitFunction )
  684. {
  685. engine->jitCompiler->ReleaseJITFunction(jitFunction);
  686. jitFunction = 0;
  687. }
  688. // Compile for native system
  689. int r = jit->CompileFunction(this, &jitFunction);
  690. if( r < 0 )
  691. {
  692. asASSERT( jitFunction == 0 );
  693. }
  694. }
  695. // interface
  696. asDWORD *asCScriptFunction::GetByteCode(asUINT *length)
  697. {
  698. if( length )
  699. *length = (asUINT)byteCode.GetLength();
  700. if( byteCode.GetLength() )
  701. {
  702. return byteCode.AddressOf();
  703. }
  704. return 0;
  705. }
  706. // interface
  707. void *asCScriptFunction::SetUserData(void *data)
  708. {
  709. void *oldData = userData;
  710. userData = data;
  711. return oldData;
  712. }
  713. // interface
  714. void *asCScriptFunction::GetUserData() const
  715. {
  716. return userData;
  717. }
  718. // internal
  719. asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr)
  720. {
  721. for( asUINT g = 0; g < engine->globalProperties.GetLength(); g++ )
  722. if( engine->globalProperties[g] && engine->globalProperties[g]->GetAddressOfValue() == gvarPtr )
  723. return engine->globalProperties[g];
  724. return 0;
  725. }
  726. // internal
  727. int asCScriptFunction::GetRefCount()
  728. {
  729. return refCount.get();
  730. }
  731. // internal
  732. void asCScriptFunction::SetFlag()
  733. {
  734. gcFlag = true;
  735. }
  736. // internal
  737. bool asCScriptFunction::GetFlag()
  738. {
  739. return gcFlag;
  740. }
  741. // internal
  742. void asCScriptFunction::EnumReferences(asIScriptEngine *)
  743. {
  744. // Notify the GC of all object types used
  745. if( returnType.IsObject() )
  746. engine->GCEnumCallback(returnType.GetObjectType());
  747. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  748. if( parameterTypes[p].IsObject() )
  749. engine->GCEnumCallback(parameterTypes[p].GetObjectType());
  750. for( asUINT t = 0; t < objVariableTypes.GetLength(); t++ )
  751. engine->GCEnumCallback(objVariableTypes[t]);
  752. // Notify the GC of all script functions that is accessed
  753. for( asUINT n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  754. {
  755. switch( *(asBYTE*)&byteCode[n] )
  756. {
  757. case asBC_OBJTYPE:
  758. case asBC_FREE:
  759. case asBC_REFCPY:
  760. {
  761. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  762. engine->GCEnumCallback(objType);
  763. }
  764. break;
  765. case asBC_ALLOC:
  766. {
  767. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  768. engine->GCEnumCallback(objType);
  769. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  770. if( func )
  771. engine->GCEnumCallback(engine->scriptFunctions[func]);
  772. }
  773. break;
  774. case asBC_CALL:
  775. case asBC_CALLINTF:
  776. {
  777. int func = asBC_INTARG(&byteCode[n]);
  778. if( func )
  779. engine->GCEnumCallback(engine->scriptFunctions[func]);
  780. }
  781. break;
  782. // Function pointers
  783. case asBC_FuncPtr:
  784. {
  785. asCScriptFunction *func = (asCScriptFunction*)(size_t)asBC_PTRARG(&byteCode[n]);
  786. if( func )
  787. engine->GCEnumCallback(func);
  788. }
  789. break;
  790. // Global variables
  791. case asBC_PGA:
  792. case asBC_LDG:
  793. case asBC_PshG4:
  794. case asBC_LdGRdR4:
  795. case asBC_CpyGtoV4:
  796. case asBC_CpyVtoG4:
  797. case asBC_SetG4:
  798. // Need to enumerate the reference for each global variable
  799. {
  800. // TODO: optimize: Keep an array of accessed global properties
  801. void *gvarPtr = (void*)(size_t)asBC_PTRARG(&byteCode[n]);
  802. asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr);
  803. engine->GCEnumCallback(prop);
  804. }
  805. break;
  806. }
  807. }
  808. }
  809. // internal
  810. void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
  811. {
  812. // Release paramaters
  813. if( byteCode.GetLength() )
  814. {
  815. if( returnType.IsObject() )
  816. {
  817. returnType.GetObjectType()->Release();
  818. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  819. }
  820. for( asUINT p = 0; p < parameterTypes.GetLength(); p++ )
  821. if( parameterTypes[p].IsObject() )
  822. {
  823. parameterTypes[p].GetObjectType()->Release();
  824. parameterTypes[p] = asCDataType::CreatePrimitive(ttInt, false);
  825. }
  826. for( asUINT n = 0; n < objVariableTypes.GetLength(); n++ )
  827. objVariableTypes[n]->Release();
  828. objVariableTypes.SetLength(0);
  829. }
  830. // Release all script functions
  831. for( asUINT n = 0; n < byteCode.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&byteCode[n]].type] )
  832. {
  833. switch( *(asBYTE*)&byteCode[n] )
  834. {
  835. // Object types
  836. case asBC_OBJTYPE:
  837. case asBC_FREE:
  838. case asBC_REFCPY:
  839. {
  840. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  841. if( objType )
  842. {
  843. objType->Release();
  844. *(void**)&byteCode[n+1] = 0;
  845. }
  846. }
  847. break;
  848. case asBC_ALLOC:
  849. {
  850. asCObjectType *objType = (asCObjectType*)(size_t)asBC_PTRARG(&byteCode[n]);
  851. if( objType )
  852. {
  853. objType->Release();
  854. * (void**)&byteCode[n+1] = 0;
  855. }
  856. int func = asBC_INTARG(&byteCode[n]+AS_PTR_SIZE);
  857. if( func )
  858. {
  859. engine->scriptFunctions[func]->Release();
  860. byteCode[n+AS_PTR_SIZE+1] = 0;
  861. }
  862. }
  863. break;
  864. case asBC_CALL:
  865. case asBC_CALLINTF:
  866. {
  867. int func = asBC_INTARG(&byteCode[n]);
  868. if( func )
  869. {
  870. engine->scriptFunctions[func]->Release();
  871. byteCode[n+1] = 0;
  872. }
  873. }
  874. break;
  875. // Function pointers
  876. case asBC_FuncPtr:
  877. {
  878. asCScriptFunction *func = (asCScriptFunction*)(size_t)asBC_PTRARG(&byteCode[n]);
  879. if( func )
  880. {
  881. func->Release();
  882. *(size_t*)&byteCode[n+1] = 0;
  883. }
  884. }
  885. break;
  886. // The global variables are not released here. It is enough that the global
  887. // variable itself release the function to break the circle
  888. }
  889. }
  890. }
  891. // internal
  892. bool asCScriptFunction::IsShared() const
  893. {
  894. // All system functions are shared
  895. if( funcType == asFUNC_SYSTEM ) return true;
  896. // All class methods for shared classes are also shared
  897. if( objectType && (objectType->flags & asOBJ_SHARED) ) return true;
  898. // Functions that have been specifically marked as shared are shared
  899. return isShared;
  900. }
  901. END_AS_NAMESPACE