12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889 |
- /*
- AngelCode Scripting Library
- Copyright (c) 2003-2021 Andreas Jonsson
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- The original version of this library can be located at:
- http://www.angelcode.com/angelscript/
- Andreas Jonsson
- andreas@angelcode.com
- */
- //
- // as_module.cpp
- //
- // A class that holds a script module
- //
- #include "as_config.h"
- #include "as_module.h"
- #include "as_builder.h"
- #include "as_context.h"
- #include "as_texts.h"
- #include "as_debug.h"
- #include "as_restore.h"
- BEGIN_AS_NAMESPACE
- // internal
- asCModule::asCModule(const char *name, asCScriptEngine *engine)
- {
- m_name = name;
- m_engine = engine;
- m_userData = 0;
- m_builder = 0;
- m_isGlobalVarInitialized = false;
- m_accessMask = 1;
- m_defaultNamespace = engine->nameSpaces[0];
- }
- // internal
- asCModule::~asCModule()
- {
- InternalReset();
- // The builder is not removed by InternalReset because it holds the script
- // sections that will be built, so we need to explictly remove it now if it exists
- if( m_builder )
- {
- asDELETE(m_builder,asCBuilder);
- m_builder = 0;
- }
- if( m_engine )
- {
- // Clean the user data
- for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
- {
- if( m_userData[n+1] )
- {
- for( asUINT c = 0; c < m_engine->cleanModuleFuncs.GetLength(); c++ )
- if( m_engine->cleanModuleFuncs[c].type == m_userData[n] )
- m_engine->cleanModuleFuncs[c].cleanFunc(this);
- }
- }
- // Remove the module from the engine
- ACQUIREEXCLUSIVE(m_engine->engineRWLock);
- // The module must have been discarded before it is deleted
- asASSERT( !m_engine->scriptModules.Exists(this) );
- m_engine->discardedModules.RemoveValue(this);
- RELEASEEXCLUSIVE(m_engine->engineRWLock);
- }
- }
- // interface
- void asCModule::Discard()
- {
- // Reset the global variables already so that no object in the global variables keep the module alive forever.
- // If any live object tries to access the global variables during clean up they will fail with a script exception,
- // so the application must keep that in mind before discarding a module.
- CallExit();
- // Keep a local copy of the engine pointer, because once the module is moved do the discarded
- // pile, it is possible that another thread might discard it while we are still in here. So no
- // further access to members may be done after that
- asCScriptEngine *engine = m_engine;
- // Instead of deleting the module immediately, move it to the discarded pile
- // This will turn it invisible to the application, yet keep it alive until all
- // external references to its entities have been released.
- ACQUIREEXCLUSIVE(engine->engineRWLock);
- if( engine->lastModule == this )
- engine->lastModule = 0;
- engine->scriptModules.RemoveValue(this);
- engine->discardedModules.PushLast(this);
- RELEASEEXCLUSIVE(engine->engineRWLock);
- // Allow the engine to go over the list of discarded modules to see what can be cleaned up at this moment.
- // Don't do this if the engine is already shutting down, as it will be done explicitly by the engine itself with error reporting
- if( !engine->shuttingDown )
- {
- if( engine->ep.autoGarbageCollect )
- engine->GarbageCollect();
- else
- {
- // GarbageCollect calls DeleteDiscardedModules, so no need
- // to call it again if we already called GarbageCollect
- engine->DeleteDiscardedModules();
- }
- }
- }
- // interface
- void *asCModule::SetUserData(void *data, asPWORD type)
- {
- // As a thread might add a new new user data at the same time as another
- // it is necessary to protect both read and write access to the userData member
- ACQUIREEXCLUSIVE(m_engine->engineRWLock);
- // It is not intended to store a lot of different types of userdata,
- // so a more complex structure like a associative map would just have
- // more overhead than a simple array.
- for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
- {
- if( m_userData[n] == type )
- {
- void *oldData = reinterpret_cast<void*>(m_userData[n+1]);
- m_userData[n+1] = reinterpret_cast<asPWORD>(data);
- RELEASEEXCLUSIVE(m_engine->engineRWLock);
- return oldData;
- }
- }
- m_userData.PushLast(type);
- m_userData.PushLast(reinterpret_cast<asPWORD>(data));
- RELEASEEXCLUSIVE(m_engine->engineRWLock);
- return 0;
- }
- // interface
- void *asCModule::GetUserData(asPWORD type) const
- {
- // There may be multiple threads reading, but when
- // setting the user data nobody must be reading.
- ACQUIRESHARED(m_engine->engineRWLock);
- for( asUINT n = 0; n < m_userData.GetLength(); n += 2 )
- {
- if( m_userData[n] == type )
- {
- void *ud = reinterpret_cast<void*>(m_userData[n+1]);
- RELEASESHARED(m_engine->engineRWLock);
- return ud;
- }
- }
- RELEASESHARED(m_engine->engineRWLock);
- return 0;
- }
- // interface
- asIScriptEngine *asCModule::GetEngine() const
- {
- return m_engine;
- }
- // interface
- void asCModule::SetName(const char *in_name)
- {
- m_name = in_name;
- }
- // interface
- const char *asCModule::GetName() const
- {
- return m_name.AddressOf();
- }
- // interface
- const char *asCModule::GetDefaultNamespace() const
- {
- return m_defaultNamespace->name.AddressOf();
- }
- // interface
- int asCModule::SetDefaultNamespace(const char *nameSpace)
- {
- // TODO: cleanup: This function is similar to asCScriptEngine::SetDefaultNamespace. Can we reuse the code?
- if( nameSpace == 0 )
- return asINVALID_ARG;
- asCString ns = nameSpace;
- if( ns != "" )
- {
- // Make sure the namespace is composed of alternating identifier and ::
- size_t pos = 0;
- bool expectIdentifier = true;
- size_t len;
- eTokenType t = ttIdentifier;
- for( ; pos < ns.GetLength(); pos += len )
- {
- t = m_engine->tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len);
- if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) )
- return asINVALID_DECLARATION;
- expectIdentifier = !expectIdentifier;
- }
- // If the namespace ends with :: then strip it off
- if( t == ttScope )
- ns.SetLength(ns.GetLength()-2);
- }
- m_defaultNamespace = m_engine->AddNameSpace(ns.AddressOf());
- return 0;
- }
- // interface
- int asCModule::AddScriptSection(const char *in_name, const char *in_code, size_t in_codeLength, int in_lineOffset)
- {
- #ifdef AS_NO_COMPILER
- UNUSED_VAR(in_name);
- UNUSED_VAR(in_code);
- UNUSED_VAR(in_codeLength);
- UNUSED_VAR(in_lineOffset);
- return asNOT_SUPPORTED;
- #else
- if( !m_builder )
- {
- m_builder = asNEW(asCBuilder)(m_engine, this);
- if( m_builder == 0 )
- return asOUT_OF_MEMORY;
- }
- return m_builder->AddCode(in_name, in_code, (int)in_codeLength, in_lineOffset, (int)m_engine->GetScriptSectionNameIndex(in_name ? in_name : ""), m_engine->ep.copyScriptSections);
- #endif
- }
- // internal
- void asCModule::JITCompile()
- {
- asIJITCompiler *jit = m_engine->GetJITCompiler();
- if( !jit )
- return;
- for (unsigned int i = 0; i < m_scriptFunctions.GetLength(); i++)
- m_scriptFunctions[i]->JITCompile();
- }
- // interface
- int asCModule::Build()
- {
- #ifdef AS_NO_COMPILER
- return asNOT_SUPPORTED;
- #else
- TimeIt("asCModule::Build");
- // Don't allow the module to be rebuilt if there are still
- // external references that will need the previous code
- // TODO: interface: The asIScriptModule must have a method for querying if the module is used
- if( HasExternalReferences(false) )
- {
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
- return asMODULE_IS_IN_USE;
- }
- // Only one thread may build at one time
- // TODO: It should be possible to have multiple threads perform compilations
- int r = m_engine->RequestBuild();
- if( r < 0 )
- return r;
- m_engine->PrepareEngine();
- if( m_engine->configFailed )
- {
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION);
- m_engine->BuildCompleted();
- return asINVALID_CONFIGURATION;
- }
- InternalReset();
- if( !m_builder )
- {
- m_engine->BuildCompleted();
- return asSUCCESS;
- }
- // Compile the script
- r = m_builder->Build();
- asDELETE(m_builder,asCBuilder);
- m_builder = 0;
- if( r < 0 )
- {
- // Reset module again
- InternalReset();
- m_engine->BuildCompleted();
- return r;
- }
- JITCompile();
- m_engine->PrepareEngine();
- #ifdef AS_DEBUG
- // Verify that there are no unwanted gaps in the scriptFunctions array.
- for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ )
- {
- int id = n;
- if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) )
- asASSERT( false );
- }
- #endif
- m_engine->BuildCompleted();
- // Initialize global variables
- if( r >= 0 && m_engine->ep.initGlobalVarsAfterBuild )
- r = ResetGlobalVars(0);
- return r;
- #endif
- }
- // interface
- int asCModule::ResetGlobalVars(asIScriptContext *ctx)
- {
- if( m_isGlobalVarInitialized )
- CallExit();
- return CallInit(ctx);
- }
- // interface
- asIScriptFunction *asCModule::GetFunctionByIndex(asUINT index) const
- {
- return const_cast<asCScriptFunction*>(m_globalFunctions.Get(index));
- }
- // internal
- int asCModule::CallInit(asIScriptContext *myCtx)
- {
- if( m_isGlobalVarInitialized )
- return asERROR;
- // Each global variable needs to be cleared individually
- asCSymbolTableIterator<asCGlobalProperty> it = m_scriptGlobals.List();
- while( it )
- {
- asCGlobalProperty *desc = *it;
- memset(desc->GetAddressOfValue(), 0, sizeof(asDWORD)*desc->type.GetSizeOnStackDWords());
- it++;
- }
- // Call the init function for each of the global variables
- asIScriptContext *ctx = myCtx;
- int r = asEXECUTION_FINISHED;
- it = m_scriptGlobals.List();
- while( it && r == asEXECUTION_FINISHED )
- {
- asCGlobalProperty *desc = *it;
- it++;
- if( desc->GetInitFunc() )
- {
- if( ctx == 0 )
- {
- ctx = m_engine->RequestContext();
- if( ctx == 0 )
- break;
- }
- r = InitGlobalProp(desc, ctx);
- }
- }
- if( ctx && !myCtx )
- {
- m_engine->ReturnContext(ctx);
- ctx = 0;
- }
- // Even if the initialization failed we need to set the
- // flag that the variables have been initialized, otherwise
- // the module won't free those variables that really were
- // initialized.
- m_isGlobalVarInitialized = true;
- if( r != asEXECUTION_FINISHED )
- return asINIT_GLOBAL_VARS_FAILED;
- return asSUCCESS;
- }
- // internal
- // This function assumes the memory for the global property is already cleared
- int asCModule::InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *myCtx)
- {
- // Call the init function for each of the global variables
- asIScriptContext *ctx = myCtx;
- int r = asEXECUTION_FINISHED;
- if( prop->GetInitFunc() )
- {
- if( ctx == 0 )
- {
- ctx = m_engine->RequestContext();
- if( ctx == 0 )
- return asERROR;
- }
- r = ctx->Prepare(prop->GetInitFunc());
- if( r >= 0 )
- {
- r = ctx->Execute();
- if( r != asEXECUTION_FINISHED )
- {
- asCString msg;
- msg.Format(TXT_FAILED_TO_INITIALIZE_s, prop->name.AddressOf());
- asCScriptFunction *func = prop->GetInitFunc();
- m_engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? m_engine->scriptSectionNames[func->scriptData->scriptSectionIdx]->AddressOf() : "",
- func->GetLineNumber(0, 0) & 0xFFFFF,
- func->GetLineNumber(0, 0) >> 20,
- asMSGTYPE_ERROR,
- msg.AddressOf());
- if( r == asEXECUTION_EXCEPTION )
- {
- const asIScriptFunction *function = ctx->GetExceptionFunction();
- msg.Format(TXT_EXCEPTION_s_IN_s, ctx->GetExceptionString(), function->GetDeclaration());
- m_engine->WriteMessage(function->GetScriptSectionName(),
- ctx->GetExceptionLineNumber(),
- 0,
- asMSGTYPE_INFORMATION,
- msg.AddressOf());
- }
- }
- }
- }
- if( ctx && !myCtx )
- {
- m_engine->ReturnContext(ctx);
- ctx = 0;
- }
- // Even if the initialization failed we need to set the
- // flag that the variables have been initialized, otherwise
- // the module won't free those variables that really were
- // initialized.
- m_isGlobalVarInitialized = true;
- if( r != asEXECUTION_FINISHED )
- return asINIT_GLOBAL_VARS_FAILED;
- return asSUCCESS;
- }
- // internal
- void asCModule::UninitializeGlobalProp(asCGlobalProperty *prop)
- {
- if (prop == 0)
- return;
- if (prop->type.IsObject())
- {
- void **obj = (void**)prop->GetAddressOfValue();
- if (*obj)
- {
- asCObjectType *ot = CastToObjectType(prop->type.GetTypeInfo());
- if (ot->flags & asOBJ_REF)
- {
- asASSERT((ot->flags & asOBJ_NOCOUNT) || ot->beh.release);
- if (ot->beh.release)
- m_engine->CallObjectMethod(*obj, ot->beh.release);
- }
- else
- {
- if (ot->beh.destruct)
- m_engine->CallObjectMethod(*obj, ot->beh.destruct);
- m_engine->CallFree(*obj);
- }
- // Set the address to 0 as someone might try to access the variable afterwards
- *obj = 0;
- }
- }
- else if (prop->type.IsFuncdef())
- {
- asCScriptFunction **func = (asCScriptFunction**)prop->GetAddressOfValue();
- if (*func)
- {
- (*func)->Release();
- *func = 0;
- }
- }
- }
- // internal
- void asCModule::CallExit()
- {
- if( !m_isGlobalVarInitialized ) return;
- asCSymbolTableIterator<asCGlobalProperty> it = m_scriptGlobals.List();
- while( it )
- {
- UninitializeGlobalProp(*it);
- it++;
- }
- m_isGlobalVarInitialized = false;
- }
- // internal
- bool asCModule::HasExternalReferences(bool shuttingDown)
- {
- // Check all entities in the module for any external references.
- // If there are any external references the module cannot be deleted yet.
- asCSymbolTableIterator<asCGlobalProperty> it = m_scriptGlobals.List();
- while (it)
- {
- asCGlobalProperty *desc = *it;
- if (desc->GetInitFunc() && desc->GetInitFunc()->externalRefCount.get())
- {
- if( !shuttingDown )
- return true;
- else
- {
- asCString msg;
- msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
- // TODO: Use a better error message
- asCString tmpName = "init " + desc->name;
- msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, tmpName.AddressOf(), desc->GetInitFunc()->GetFuncType());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
- }
- }
- it++;
- }
- for (asUINT n = 0; n < m_scriptFunctions.GetLength(); n++)
- {
- asCScriptFunction *func = m_scriptFunctions[n];
- if (func && func->externalRefCount.get())
- {
- // If the func is shared and can be moved to another module then this is not a reason to keep the module alive
- if (func->IsShared() && m_engine->FindNewOwnerForSharedFunc(func, this) != this)
- continue;
- if (!shuttingDown)
- return true;
- else
- {
- asCString msg;
- msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
- msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_scriptFunctions[n]->GetName(), m_scriptFunctions[n]->GetFuncType());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
- }
- }
- }
- for (asUINT n = 0; n < m_classTypes.GetLength(); n++)
- {
- asCObjectType *obj = m_classTypes[n];
- if (obj && obj->externalRefCount.get())
- {
- // If the obj is shared and can be moved to another module then this is not a reason to keep the module alive
- if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this)
- continue;
- if (!shuttingDown)
- return true;
- else
- {
- asCString msg;
- msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
- msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_classTypes[n]->GetName());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
- }
- }
- }
- for (asUINT n = 0; n < m_funcDefs.GetLength(); n++)
- {
- asCFuncdefType *func = m_funcDefs[n];
- if (func && func->externalRefCount.get())
- {
- // If the funcdef is shared and can be moved to another module then this is not a reason to keep the module alive
- if (func->IsShared() && m_engine->FindNewOwnerForSharedType(func, this) != this)
- continue;
- if (!shuttingDown)
- return true;
- else
- {
- asCString msg;
- msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
- msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_funcDefs[n]->GetName(), m_funcDefs[n]->funcdef->GetFuncType());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
- }
- }
- }
- for (asUINT n = 0; n < m_templateInstances.GetLength(); n++)
- {
- asCObjectType *obj = m_templateInstances[n];
- if (obj && obj->externalRefCount.get())
- {
- // If the template can be moved to another module then this is not a reason to keep the module alive
- if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this)
- continue;
- if (!shuttingDown)
- return true;
- else
- {
- asCString msg;
- msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf());
- msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_templateInstances[n]->GetName());
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf());
- }
- }
- }
- return false;
- }
- // internal
- void asCModule::InternalReset()
- {
- CallExit();
- asUINT n;
- // Remove all global functions
- m_globalFunctions.Clear();
- // Destroy the internals of the global properties here, but do not yet remove them from the
- // engine, because functions need the engine's varAddressMap to get to the property. If the
- // property is removed already, it may leak as the refCount doesn't reach 0.
- asCSymbolTableIterator<asCGlobalProperty> globIt = m_scriptGlobals.List();
- while( globIt )
- {
- (*globIt)->DestroyInternal();
- globIt++;
- }
- UnbindAllImportedFunctions();
- // Free bind information
- for( n = 0; n < m_bindInformations.GetLength(); n++ )
- {
- if( m_bindInformations[n] )
- {
- m_bindInformations[n]->importedFunctionSignature->ReleaseInternal();
- asDELETE(m_bindInformations[n], sBindInfo);
- }
- }
- m_bindInformations.SetLength(0);
- // Free declared types, including classes, typedefs, and enums
- for( n = 0; n < m_templateInstances.GetLength(); n++ )
- {
- asCObjectType *type = m_templateInstances[n];
- if( m_engine->FindNewOwnerForSharedType(type, this) != this )
- {
- // The type is owned by another module, just release our reference
- type->ReleaseInternal();
- continue;
- }
- // Orphan the template instance
- type->module = 0;
- // No other module is holding the template type
- m_engine->RemoveTemplateInstanceType(type);
- type->ReleaseInternal();
- }
- m_templateInstances.SetLength(0);
- for( n = 0; n < m_classTypes.GetLength(); n++ )
- {
- asCObjectType *type = m_classTypes[n];
- if( type->IsShared() )
- {
- // The type is shared, so transfer ownership to another module that also uses it
- if( m_engine->FindNewOwnerForSharedType(type, this) != this )
- {
- // The type is owned by another module, just release our reference
- type->ReleaseInternal();
- continue;
- }
- }
- // The type should be destroyed now
- type->DestroyInternal();
- // Remove the type from the engine
- if( type->IsShared() )
- {
- m_engine->sharedScriptTypes.RemoveValue(type);
- type->ReleaseInternal();
- }
- // Release it from the module
- type->module = 0;
- type->ReleaseInternal();
- }
- m_classTypes.SetLength(0);
- for( n = 0; n < m_enumTypes.GetLength(); n++ )
- {
- asCEnumType *type = m_enumTypes[n];
- if( type->IsShared() )
- {
- // The type is shared, so transfer ownership to another module that also uses it
- if( m_engine->FindNewOwnerForSharedType(type, this) != this )
- {
- // The type is owned by another module, just release our reference
- type->ReleaseInternal();
- continue;
- }
- }
- // Remove the type from the engine
- if( type->IsShared() )
- {
- m_engine->sharedScriptTypes.RemoveValue(type);
- type->ReleaseInternal();
- }
- // Release it from the module
- type->module = 0;
- type->ReleaseInternal();
- }
- m_enumTypes.SetLength(0);
- for( n = 0; n < m_typeDefs.GetLength(); n++ )
- {
- asCTypedefType *type = m_typeDefs[n];
- // The type should be destroyed now
- type->DestroyInternal();
- // Release it from the module
- type->module = 0;
- type->ReleaseInternal();
- }
- m_typeDefs.SetLength(0);
- // Free funcdefs
- for( n = 0; n < m_funcDefs.GetLength(); n++ )
- {
- asCFuncdefType *func = m_funcDefs[n];
- asASSERT(func);
- if( func->funcdef && func->funcdef->IsShared() )
- {
- // The funcdef is shared, so transfer ownership to another module that also uses it
- if( m_engine->FindNewOwnerForSharedType(func, this) != this )
- {
- // The funcdef is owned by another module, just release our reference
- func->ReleaseInternal();
- continue;
- }
- }
- func->DestroyInternal();
- m_engine->RemoveFuncdef(func);
- func->module = 0;
- func->ReleaseInternal();
- }
- m_funcDefs.SetLength(0);
- // Then release the functions
- for( n = 0; n < m_scriptFunctions.GetLength(); n++ )
- {
- asCScriptFunction *func = m_scriptFunctions[n];
- if( func->IsShared() )
- {
- // The func is shared, so transfer ownership to another module that also uses it
- if( m_engine->FindNewOwnerForSharedFunc(func, this) != this )
- {
- // The func is owned by another module, just release our reference
- func->ReleaseInternal();
- continue;
- }
- }
- func->DestroyInternal();
- func->module = 0;
- func->ReleaseInternal();
- }
- m_scriptFunctions.SetLength(0);
- // Now remove and release the global properties as there are no more references to them
- globIt = m_scriptGlobals.List();
- while( globIt )
- {
- m_engine->RemoveGlobalProperty(*globIt);
- asASSERT( (*globIt)->refCount.get() == 1 );
- (*globIt)->Release();
- globIt++;
- }
- m_scriptGlobals.Clear();
- // Clear the type lookup
- // The references were already released as the types were removed from the respective arrays
- m_typeLookup.EraseAll();
- asASSERT( IsEmpty() );
- }
- // interface
- asIScriptFunction *asCModule::GetFunctionByName(const char *in_name) const
- {
- asCString name;
- asSNameSpace *ns = 0;
- if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 )
- return 0;
-
- // Search recursively in the given namespace, moving up to parent namespace until the function is found
- while( ns )
- {
- const asCArray<unsigned int> &idxs = m_globalFunctions.GetIndexes(ns, name);
- if( idxs.GetLength() != 1 )
- return 0;
- const asIScriptFunction *func = m_globalFunctions.Get(idxs[0]);
- if( func )
- return const_cast<asIScriptFunction*>(func);
- // Recursively search parent namespaces
- ns = m_engine->GetParentNameSpace(ns);
- }
- return 0;
- }
- // interface
- asUINT asCModule::GetImportedFunctionCount() const
- {
- return (asUINT)m_bindInformations.GetLength();
- }
- // interface
- int asCModule::GetImportedFunctionIndexByDecl(const char *decl) const
- {
- asCBuilder bld(m_engine, const_cast<asCModule*>(this));
- // Don't write parser errors to the message callback
- bld.silent = true;
- asCScriptFunction func(m_engine, const_cast<asCModule*>(this), asFUNC_DUMMY);
- bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace);
- // TODO: optimize: Improve linear search
- // Search script functions for matching interface
- int id = -1;
- for( asUINT n = 0; n < m_bindInformations.GetLength(); ++n )
- {
- if( func.name == m_bindInformations[n]->importedFunctionSignature->name &&
- func.returnType == m_bindInformations[n]->importedFunctionSignature->returnType &&
- func.parameterTypes.GetLength() == m_bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() )
- {
- bool match = true;
- for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p )
- {
- if( func.parameterTypes[p] != m_bindInformations[n]->importedFunctionSignature->parameterTypes[p] )
- {
- match = false;
- break;
- }
- }
- if( match )
- {
- if( id == -1 )
- id = n;
- else
- return asMULTIPLE_FUNCTIONS;
- }
- }
- }
- if( id == -1 ) return asNO_FUNCTION;
- return id;
- }
- // interface
- asUINT asCModule::GetFunctionCount() const
- {
- return (asUINT)m_globalFunctions.GetSize();
- }
- // interface
- asIScriptFunction *asCModule::GetFunctionByDecl(const char *decl) const
- {
- asCBuilder bld(m_engine, const_cast<asCModule*>(this));
- // Don't write parser errors to the message callback
- bld.silent = true;
- asCScriptFunction func(m_engine, const_cast<asCModule*>(this), asFUNC_DUMMY);
- int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace);
- if( r < 0 )
- {
- // Invalid declaration
- // TODO: Write error to message stream
- return 0;
- }
- // Use the defaultNamespace implicitly unless an explicit namespace has been provided
- asSNameSpace *ns = func.nameSpace == m_engine->nameSpaces[0] ? m_defaultNamespace : func.nameSpace;
- // Search script functions for matching interface
- while( ns )
- {
- asIScriptFunction *f = 0;
- const asCArray<unsigned int> &idxs = m_globalFunctions.GetIndexes(ns, func.name);
- for( unsigned int n = 0; n < idxs.GetLength(); n++ )
- {
- const asCScriptFunction *funcPtr = m_globalFunctions.Get(idxs[n]);
- if( funcPtr->objectType == 0 &&
- func.returnType == funcPtr->returnType &&
- func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength()
- )
- {
- bool match = true;
- for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p )
- {
- if( func.parameterTypes[p] != funcPtr->parameterTypes[p] )
- {
- match = false;
- break;
- }
- }
- if( match )
- {
- if( f == 0 )
- f = const_cast<asCScriptFunction*>(funcPtr);
- else
- // Multiple functions
- return 0;
- }
- }
- }
- if( f )
- return f;
- else
- {
- // Search for matching functions in the parent namespace
- ns = m_engine->GetParentNameSpace(ns);
- }
- }
- return 0;
- }
- // interface
- asUINT asCModule::GetGlobalVarCount() const
- {
- return (asUINT)m_scriptGlobals.GetSize();
- }
- // interface
- int asCModule::GetGlobalVarIndexByName(const char *in_name) const
- {
- asCString name;
- asSNameSpace *ns = 0;
- if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 )
- return asINVALID_ARG;
-
- // Find the global var id
- while( ns )
- {
- int id = m_scriptGlobals.GetFirstIndex(ns, name);
- if( id >= 0 ) return id;
- // Recursively search parent namespaces
- ns = m_engine->GetParentNameSpace(ns);
- }
- return asNO_GLOBAL_VAR;
- }
- // interface
- int asCModule::RemoveGlobalVar(asUINT index)
- {
- asCGlobalProperty *prop = m_scriptGlobals.Get(index);
- if( !prop )
- return asINVALID_ARG;
- // If the global variables have already been initialized
- // then uninitialize the variable before it is removed
- if (m_isGlobalVarInitialized)
- UninitializeGlobalProp(prop);
- // Destroy the internal of the global variable (removes the initialization function)
- prop->DestroyInternal();
- // Check if the module is the only one referring to the property, if so remove it from the engine too
- // If the property is not removed now, it will be removed later when the module is discarded
- if( prop->refCount.get() == 2 )
- m_engine->RemoveGlobalProperty(prop);
- // Remove the global variable from the module
- m_scriptGlobals.Erase(index);
- prop->Release();
- return 0;
- }
- // interface
- int asCModule::GetGlobalVarIndexByDecl(const char *decl) const
- {
- asCBuilder bld(m_engine, const_cast<asCModule*>(this));
- // Don't write parser errors to the message callback
- bld.silent = true;
- asCString declName;
- asSNameSpace *nameSpace;
- asCDataType dt;
- int r = bld.ParseVariableDeclaration(decl, m_defaultNamespace, declName, nameSpace, dt);
- if( r < 0 )
- return r;
- // Search global variables for a match
- while( nameSpace )
- {
- int id = m_scriptGlobals.GetFirstIndex(nameSpace, declName, asCCompGlobPropType(dt));
- if( id != -1 )
- return id;
- // Recursively search parent namespace
- nameSpace = m_engine->GetParentNameSpace(nameSpace);
- }
- return asNO_GLOBAL_VAR;
- }
- // interface
- void *asCModule::GetAddressOfGlobalVar(asUINT index)
- {
- asCGlobalProperty *prop = m_scriptGlobals.Get(index);
- if( !prop )
- return 0;
- // For object variables it's necessary to dereference the pointer to get the address of the value
- if( prop->type.IsObject() &&
- !prop->type.IsObjectHandle() )
- return *(void**)(prop->GetAddressOfValue());
- return (void*)(prop->GetAddressOfValue());
- }
- // interface
- const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const
- {
- const asCGlobalProperty *prop = m_scriptGlobals.Get(index);
- if (!prop) return 0;
- asCString *tempString = &asCThreadManager::GetLocalData()->string;
- *tempString = prop->type.Format(m_defaultNamespace);
- *tempString += " ";
- if( includeNamespace && prop->nameSpace->name != "" )
- *tempString += prop->nameSpace->name + "::";
- *tempString += prop->name;
- return tempString->AddressOf();
- }
- // interface
- int asCModule::GetGlobalVar(asUINT index, const char **out_name, const char **out_nameSpace, int *out_typeId, bool *out_isConst) const
- {
- const asCGlobalProperty *prop = m_scriptGlobals.Get(index);
- if (!prop) return asINVALID_ARG;
- if( out_name )
- *out_name = prop->name.AddressOf();
- if( out_nameSpace )
- *out_nameSpace = prop->nameSpace->name.AddressOf();
- if( out_typeId )
- *out_typeId = m_engine->GetTypeIdFromDataType(prop->type);
- if( out_isConst )
- *out_isConst = prop->type.IsReadOnly();
- return asSUCCESS;
- }
- // interface
- asUINT asCModule::GetObjectTypeCount() const
- {
- return (asUINT)m_classTypes.GetLength();
- }
- // interface
- asITypeInfo *asCModule::GetObjectTypeByIndex(asUINT index) const
- {
- if( index >= m_classTypes.GetLength() )
- return 0;
- return m_classTypes[index];
- }
- // interface
- asITypeInfo *asCModule::GetTypeInfoByName(const char *in_name) const
- {
- asCString name;
- asSNameSpace *ns = 0;
- if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 )
- return 0;
-
- while (ns)
- {
- asITypeInfo* info = GetType(name, ns);
- if(info)
- {
- return info;
- }
- // Recursively search parent namespace
- ns = m_engine->GetParentNameSpace(ns);
- }
- return 0;
- }
- // interface
- int asCModule::GetTypeIdByDecl(const char *decl) const
- {
- asCDataType dt;
- // This const cast is safe since we know the engine won't be modified
- asCBuilder bld(m_engine, const_cast<asCModule*>(this));
- // Don't write parser errors to the message callback
- bld.silent = true;
- int r = bld.ParseDataType(decl, &dt, m_defaultNamespace);
- if( r < 0 )
- return asINVALID_TYPE;
- return m_engine->GetTypeIdFromDataType(dt);
- }
- // interface
- asITypeInfo *asCModule::GetTypeInfoByDecl(const char *decl) const
- {
- asCDataType dt;
- // This const cast is safe since we know the engine won't be modified
- asCBuilder bld(m_engine, const_cast<asCModule*>(this));
- // Don't write parser errors to the message callback
- bld.silent = true;
- int r = bld.ParseDataType(decl, &dt, m_defaultNamespace);
- if (r < 0)
- return 0;
- return dt.GetTypeInfo();
- }
- // interface
- asUINT asCModule::GetEnumCount() const
- {
- return m_enumTypes.GetLength();
- }
- // interface
- asITypeInfo *asCModule::GetEnumByIndex(asUINT index) const
- {
- if( index >= m_enumTypes.GetLength() )
- return 0;
- return m_enumTypes[index];
- }
- // interface
- asUINT asCModule::GetTypedefCount() const
- {
- return (asUINT)m_typeDefs.GetLength();
- }
- // interface
- asITypeInfo *asCModule::GetTypedefByIndex(asUINT index) const
- {
- if( index >= m_typeDefs.GetLength() )
- return 0;
- return m_typeDefs[index];
- }
- // internal
- int asCModule::GetNextImportedFunctionId()
- {
- // TODO: multithread: This will break if one thread if freeing a module, while another is being compiled
- if( m_engine->freeImportedFunctionIdxs.GetLength() )
- return FUNC_IMPORTED | (asUINT)m_engine->freeImportedFunctionIdxs[m_engine->freeImportedFunctionIdxs.GetLength()-1];
- return FUNC_IMPORTED | (asUINT)m_engine->importedFunctions.GetLength();
- }
- #ifndef AS_NO_COMPILER
- // internal
- int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &funcName, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asCString> ¶mNames, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, bool isInterface, asCObjectType *objType, bool isGlobalFunction, asSFunctionTraits funcTraits, asSNameSpace *ns)
- {
- asASSERT(id >= 0);
- // Store the function information
- asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, this, isInterface ? asFUNC_INTERFACE : asFUNC_SCRIPT);
- if( func == 0 )
- {
- // Free the default args
- for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
- if( defaultArgs[n] )
- asDELETE(defaultArgs[n], asCString);
- return asOUT_OF_MEMORY;
- }
- if( ns == 0 )
- ns = m_engine->nameSpaces[0];
- // All methods of shared objects are also shared
- if( objType && objType->IsShared() )
- funcTraits.SetTrait(asTRAIT_SHARED, true);
- func->name = funcName;
- func->nameSpace = ns;
- func->id = id;
- func->returnType = returnType;
- if( func->funcType == asFUNC_SCRIPT )
- {
- func->scriptData->scriptSectionIdx = sectionIdx;
- func->scriptData->declaredAt = declaredAt;
- }
- func->parameterTypes = params;
- func->parameterNames = paramNames;
- func->inOutFlags = inOutFlags;
- func->defaultArgs = defaultArgs;
- func->objectType = objType;
- if( objType )
- objType->AddRefInternal();
- func->traits = funcTraits;
- asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() );
- // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function
- asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_FINAL)) );
- asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_OVERRIDE)) );
- // The internal ref count was already set by the constructor
- m_scriptFunctions.PushLast(func);
- m_engine->AddScriptFunction(func);
- // Compute the signature id
- if( objType )
- func->ComputeSignatureId();
- // Add reference
- if( isGlobalFunction )
- m_globalFunctions.Put(func);
- return 0;
- }
- // internal
- int asCModule::AddScriptFunction(asCScriptFunction *func)
- {
- m_scriptFunctions.PushLast(func);
- func->AddRefInternal();
- m_engine->AddScriptFunction(func);
- // If the function that is being added is an already compiled shared function
- // then it is necessary to look for anonymous functions that may be declared
- // within it and add those as well
- if( func->IsShared() && func->funcType == asFUNC_SCRIPT )
- {
- // Loop through the byte code and check all the
- // asBC_FuncPtr instructions for anonymous functions
- asDWORD *bc = func->scriptData->byteCode.AddressOf();
- asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength();
- for( asUINT n = 0; n < bcLength; )
- {
- int c = *(asBYTE*)&bc[n];
- if( c == asBC_FuncPtr )
- {
- asCScriptFunction *f = reinterpret_cast<asCScriptFunction*>(asBC_PTRARG(&bc[n]));
- // Anonymous functions start with $
- // There are never two equal anonymous functions so it is not necessary to look for duplicates
- if( f && f->name[0] == '$' )
- {
- AddScriptFunction(f);
- m_globalFunctions.Put(f);
- }
- }
- n += asBCTypeSize[asBCInfo[c].type];
- }
- }
- return 0;
- }
- // internal
- int asCModule::AddImportedFunction(int id, const asCString &funcName, const asCDataType &returnType, const asCArray<asCDataType> ¶ms, const asCArray<asETypeModifiers> &inOutFlags, const asCArray<asCString *> &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName)
- {
- asASSERT(id >= 0);
- // Store the function information
- asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, this, asFUNC_IMPORTED);
- if( func == 0 )
- {
- // Free the default args
- for( asUINT n = 0; n < defaultArgs.GetLength(); n++ )
- if( defaultArgs[n] )
- asDELETE(defaultArgs[n], asCString);
- return asOUT_OF_MEMORY;
- }
- func->name = funcName;
- func->id = id;
- func->returnType = returnType;
- func->nameSpace = ns;
- func->parameterTypes = params;
- func->inOutFlags = inOutFlags;
- func->defaultArgs = defaultArgs;
- func->objectType = 0;
- func->traits = funcTraits;
- sBindInfo *info = asNEW(sBindInfo);
- if( info == 0 )
- {
- asDELETE(func, asCScriptFunction);
- return asOUT_OF_MEMORY;
- }
- info->importedFunctionSignature = func;
- info->boundFunctionId = -1;
- info->importFromModule = moduleName;
- m_bindInformations.PushLast(info);
- // Add the info to the array in the engine
- if( m_engine->freeImportedFunctionIdxs.GetLength() )
- m_engine->importedFunctions[m_engine->freeImportedFunctionIdxs.PopLast()] = info;
- else
- m_engine->importedFunctions.PushLast(info);
- return 0;
- }
- #endif
- // internal
- asCScriptFunction *asCModule::GetImportedFunction(int index) const
- {
- return m_bindInformations[index]->importedFunctionSignature;
- }
- // interface
- int asCModule::BindImportedFunction(asUINT index, asIScriptFunction *func)
- {
- // First unbind the old function
- int r = UnbindImportedFunction(index);
- if( r < 0 ) return r;
- // Must verify that the interfaces are equal
- asCScriptFunction *dst = GetImportedFunction(index);
- if( dst == 0 ) return asNO_FUNCTION;
- if( func == 0 )
- return asINVALID_ARG;
- asCScriptFunction *src = m_engine->GetScriptFunction(func->GetId());
- if( src == 0 )
- return asNO_FUNCTION;
- // Verify return type
- if( dst->returnType != src->returnType )
- return asINVALID_INTERFACE;
- if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() )
- return asINVALID_INTERFACE;
- for( asUINT n = 0; n < dst->parameterTypes.GetLength(); ++n )
- {
- if( dst->parameterTypes[n] != src->parameterTypes[n] )
- return asINVALID_INTERFACE;
- }
- m_bindInformations[index]->boundFunctionId = src->GetId();
- src->AddRefInternal();
- return asSUCCESS;
- }
- // interface
- int asCModule::UnbindImportedFunction(asUINT index)
- {
- if( index >= m_bindInformations.GetLength() )
- return asINVALID_ARG;
- // Remove reference to old module
- if( m_bindInformations[index] )
- {
- int oldFuncID = m_bindInformations[index]->boundFunctionId;
- if( oldFuncID != -1 )
- {
- m_bindInformations[index]->boundFunctionId = -1;
- m_engine->scriptFunctions[oldFuncID]->ReleaseInternal();
- }
- }
- return asSUCCESS;
- }
- // interface
- const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const
- {
- asCScriptFunction *func = GetImportedFunction(index);
- if( func == 0 ) return 0;
- asCString *tempString = &asCThreadManager::GetLocalData()->string;
- // TODO: Allow the application to decide if the parameter name should be included or not (requires change in the interface)
- *tempString = func->GetDeclarationStr(true, true, false);
- return tempString->AddressOf();
- }
- // interface
- const char *asCModule::GetImportedFunctionSourceModule(asUINT index) const
- {
- if( index >= m_bindInformations.GetLength() )
- return 0;
- return m_bindInformations[index]->importFromModule.AddressOf();
- }
- // inteface
- int asCModule::BindAllImportedFunctions()
- {
- bool notAllFunctionsWereBound = false;
- // Bind imported functions
- int c = GetImportedFunctionCount();
- for( int n = 0; n < c; ++n )
- {
- asCScriptFunction *importFunc = GetImportedFunction(n);
- if( importFunc == 0 ) return asERROR;
- asCString str = importFunc->GetDeclarationStr(false, true);
- // Get module name from where the function should be imported
- const char *moduleName = GetImportedFunctionSourceModule(n);
- if( moduleName == 0 ) return asERROR;
- asCModule *srcMod = m_engine->GetModule(moduleName, false);
- asIScriptFunction *func = 0;
- if( srcMod )
- func = srcMod->GetFunctionByDecl(str.AddressOf());
- if( func == 0 )
- notAllFunctionsWereBound = true;
- else
- {
- if( BindImportedFunction(n, func) < 0 )
- notAllFunctionsWereBound = true;
- }
- }
- if( notAllFunctionsWereBound )
- return asCANT_BIND_ALL_FUNCTIONS;
- return asSUCCESS;
- }
- // interface
- int asCModule::UnbindAllImportedFunctions()
- {
- asUINT c = GetImportedFunctionCount();
- for( asUINT n = 0; n < c; ++n )
- UnbindImportedFunction(n);
- return asSUCCESS;
- }
- // internal
- void asCModule::AddClassType(asCObjectType* type)
- {
- m_classTypes.PushLast(type);
- m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
- }
- // internal
- void asCModule::AddEnumType(asCEnumType* type)
- {
- m_enumTypes.PushLast(type);
- m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
- }
- // internal
- void asCModule::AddTypeDef(asCTypedefType* type)
- {
- m_typeDefs.PushLast(type);
- m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
- }
- // internal
- void asCModule::AddFuncDef(asCFuncdefType* type)
- {
- m_funcDefs.PushLast(type);
- m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type);
- }
- // internal
- void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType)
- {
- int i = m_funcDefs.IndexOf(type);
- if( i >= 0 )
- {
- m_funcDefs[i] = newType;
-
- // Replace it in the lookup map too
- asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
- if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(type->nameSpace, type->name)))
- {
- asASSERT( result->value == type );
- result->value = newType;
- }
- }
- }
- // internal
- asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const
- {
- asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
- if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type)))
- {
- return result->value;
- }
- return 0;
- }
- // internal
- asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const
- {
- asSMapNode<asSNameSpaceNamePair, asCTypeInfo*>* result = 0;
- if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type)))
- {
- return CastToObjectType(result->value);
- }
-
- return 0;
- }
- // internal
- asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *propName, const asCDataType &dt, asSNameSpace *ns)
- {
- asCGlobalProperty *prop = m_engine->AllocateGlobalProperty();
- prop->name = propName;
- prop->nameSpace = ns;
- // Allocate the memory for this property based on its type
- prop->type = dt;
- prop->AllocateMemory();
- // Make an entry in the address to variable map
- m_engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop);
- // Store the variable in the module scope
- m_scriptGlobals.Put(prop);
- prop->AddRef();
- return prop;
- }
- // internal
- bool asCModule::IsEmpty() const
- {
- if( m_scriptFunctions.GetLength() ) return false;
- if( m_globalFunctions.GetSize() ) return false;
- if( m_bindInformations.GetLength() ) return false;
- if( m_scriptGlobals.GetSize() ) return false;
- if( m_classTypes.GetLength() ) return false;
- if( m_enumTypes.GetLength() ) return false;
- if( m_typeDefs.GetLength() ) return false;
- if( m_funcDefs.GetLength() ) return false;
- return true;
- }
- // interface
- int asCModule::SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const
- {
- #ifdef AS_NO_COMPILER
- UNUSED_VAR(out);
- UNUSED_VAR(stripDebugInfo);
- return asNOT_SUPPORTED;
- #else
- if( out == 0 ) return asINVALID_ARG;
- // Make sure there is actually something to save
- if( IsEmpty() )
- return asERROR;
- asCWriter write(const_cast<asCModule*>(this), out, m_engine, stripDebugInfo);
- return write.Write();
- #endif
- }
- // interface
- int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped)
- {
- if( in == 0 ) return asINVALID_ARG;
- // Don't allow the module to be rebuilt if there are still
- // external references that will need the previous code
- if( HasExternalReferences(false) )
- {
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE);
- return asMODULE_IS_IN_USE;
- }
- // Only permit loading bytecode if no other thread is currently compiling
- // TODO: It should be possible to have multiple threads perform compilations
- int r = m_engine->RequestBuild();
- if( r < 0 )
- return r;
- asCReader read(this, in, m_engine);
- r = read.Read(wasDebugInfoStripped);
- if (r < 0)
- {
- m_engine->BuildCompleted();
- return r;
- }
- JITCompile();
- #ifdef AS_DEBUG
- // Verify that there are no unwanted gaps in the scriptFunctions array.
- for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ )
- {
- int id = n;
- if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) )
- asASSERT( false );
- }
- #endif
- m_engine->BuildCompleted();
- return r;
- }
- // interface
- int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset)
- {
- #ifdef AS_NO_COMPILER
- UNUSED_VAR(sectionName);
- UNUSED_VAR(code);
- UNUSED_VAR(lineOffset);
- return asNOT_SUPPORTED;
- #else
- // Validate arguments
- if( code == 0 )
- return asINVALID_ARG;
- // Only one thread may build at one time
- // TODO: It should be possible to have multiple threads perform compilations
- int r = m_engine->RequestBuild();
- if( r < 0 )
- return r;
- // Prepare the engine
- m_engine->PrepareEngine();
- if( m_engine->configFailed )
- {
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION);
- m_engine->BuildCompleted();
- return asINVALID_CONFIGURATION;
- }
- // Compile the global variable and add it to the module scope
- asCBuilder varBuilder(m_engine, this);
- asCString str = code;
- r = varBuilder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset);
- m_engine->BuildCompleted();
- // Initialize the variable
- if( r >= 0 )
- {
- // Clear the memory
- asCGlobalProperty *prop = m_scriptGlobals.GetLast();
- if( prop )
- {
- memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords());
- }
- if( prop && m_engine->ep.initGlobalVarsAfterBuild )
- {
- // Flag that there are initialized global variables
- m_isGlobalVarInitialized = true;
- r = InitGlobalProp(prop, 0);
- }
- }
- return r;
- #endif
- }
- // interface
- int asCModule::CompileFunction(const char* sectionName, const char* code, int lineOffset, asDWORD compileFlags, asIScriptFunction** outFunc)
- {
- // Make sure the outFunc is null if the function fails, so the
- // application doesn't attempt to release a non-existent function
- if (outFunc)
- *outFunc = 0;
- #ifdef AS_NO_COMPILER
- UNUSED_VAR(sectionName);
- UNUSED_VAR(code);
- UNUSED_VAR(lineOffset);
- UNUSED_VAR(compileFlags);
- return asNOT_SUPPORTED;
- #else
- // Validate arguments
- if (code == 0 ||
- (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE))
- return asINVALID_ARG;
- // Only one thread may build at one time
- // TODO: It should be possible to have multiple threads perform compilations
- int r = m_engine->RequestBuild();
- if (r < 0)
- return r;
- // Prepare the engine
- m_engine->PrepareEngine();
- if (m_engine->configFailed)
- {
- m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION);
- m_engine->BuildCompleted();
- return asINVALID_CONFIGURATION;
- }
- // Compile the single function
- asCBuilder funcBuilder(m_engine, this);
- asCString str = code;
- asCScriptFunction* func = 0;
- r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func);
- if (r >= 0)
- {
- // Invoke the JIT compiler if it has been set
- asIJITCompiler* jit = m_engine->GetJITCompiler();
- if (jit)
- {
- func->JITCompile();
- }
- }
- m_engine->BuildCompleted();
- if( r >= 0 && outFunc && func )
- {
- // Return the function to the caller and add an external reference
- *outFunc = func;
- func->AddRef();
- }
- // Release our reference to the function
- if( func )
- func->ReleaseInternal();
- return r;
- #endif
- }
- // interface
- int asCModule::RemoveFunction(asIScriptFunction *func)
- {
- // Find the global function
- asCScriptFunction *f = static_cast<asCScriptFunction*>(func);
- int idx = m_globalFunctions.GetIndex(f);
- if( idx >= 0 )
- {
- m_globalFunctions.Erase(idx);
- m_scriptFunctions.RemoveValue(f);
- f->ReleaseInternal();
- return 0;
- }
- return asNO_FUNCTION;
- }
- #ifndef AS_NO_COMPILER
- // internal
- int asCModule::AddFuncDef(const asCString &funcName, asSNameSpace *ns, asCObjectType *parent)
- {
- // namespace and parent are mutually exclusive
- asASSERT((ns == 0 && parent) || (ns && parent == 0));
- asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, 0, asFUNC_FUNCDEF);
- if (func == 0)
- return asOUT_OF_MEMORY;
- func->name = funcName;
- func->nameSpace = ns;
- func->module = this;
- asCFuncdefType *fdt = asNEW(asCFuncdefType)(m_engine, func);
- AddFuncDef(fdt); // The constructor set the refcount to 1
- m_engine->funcDefs.PushLast(fdt); // doesn't increase refcount
- func->id = m_engine->GetNextScriptFunctionId();
- m_engine->AddScriptFunction(func);
- if (parent)
- {
- parent->childFuncDefs.PushLast(fdt);
- fdt->parentClass = parent;
- }
- return (int)m_funcDefs.GetLength()-1;
- }
- #endif
- // interface
- asDWORD asCModule::SetAccessMask(asDWORD mask)
- {
- asDWORD old = m_accessMask;
- m_accessMask = mask;
- return old;
- }
- END_AS_NAMESPACE
|