as_scriptfunction.cpp 28 KB

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