as_scriptfunction.cpp 31 KB

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