as_scriptfunction.cpp 31 KB

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