as_scriptfunction.cpp 29 KB

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