Remove references to functions defined in unloading defs (#1776)

directional-lights
Nicolas Hake 2016-07-06 14:20:54 +02:00
parent ab1e6bd5a4
commit f7a04624eb
5 changed files with 54 additions and 2 deletions

View File

@ -319,11 +319,11 @@ C4Def::~C4Def()
void C4Def::Clear()
{
Script.Clear();
C4PropList::Clear();
Graphics.Clear();
Script.Clear();
StringTable.Clear();
if (pClonkNames && fClonkNamesOwned) delete pClonkNames; pClonkNames=NULL;
if (pRankNames && fRankNamesOwned) delete pRankNames; pRankNames=NULL;

View File

@ -463,6 +463,7 @@ void C4AulCompiler::PreparseAstVisitor::visit(const ::aul::ast::FunctionDecl *n)
C4AulFunc *parent_func = Parent->GetFunc(cname);
Fn = new C4AulScriptFunc(Parent, target_host, cname, n->loc);
host->ownedFunctions.insert(Fn);
for (const auto &param : n->params)
{
Fn->AddPar(param.name.c_str(), param.type);

View File

@ -53,7 +53,7 @@ class C4AulFunc: public C4RefCnt
public:
C4AulFunc(C4PropListStatic * Parent, const char *pName);
const C4PropListStatic * Parent;
C4PropListStatic * Parent;
const char * GetName() const { return Name ? Name->GetCStr() : 0; }
virtual StdStrBuf GetFullName() const; // get a fully classified name (C4ID::Name) for debug output

View File

@ -52,6 +52,7 @@ C4ScriptHost::~C4ScriptHost()
void C4ScriptHost::Clear()
{
UnlinkOwnedFunctions();
C4ComponentHost::Clear();
ast.reset();
Script.Clear();
@ -70,6 +71,49 @@ void C4ScriptHost::Clear()
State = ASS_NONE;
}
void C4ScriptHost::UnlinkOwnedFunctions()
{
// Remove owned functions from their parents. This solves a problem
// where overloading a definition would unload the C4ScriptHost, but
// keep around global functions, which then contained dangling pointers.
for (auto func : ownedFunctions)
{
C4PropList *parent = func->Parent;
if (parent == GetPropList())
continue;
assert(parent == &::ScriptEngine);
C4Value v;
parent->GetPropertyByS(func->Name, &v);
if (v.getFunction() == func)
{
// If the function we're deleting is the top-level function in
// the inheritance chain, promote the next one in its stead;
// if there is no overloaded function, remove the property.
if (func->OwnerOverloaded)
parent->SetPropertyByS(func->Name, C4VFunction(func->OwnerOverloaded));
else
parent->ResetProperty(func->Name);
}
else
{
C4AulScriptFunc *func_chain = v.getFunction()->SFunc();
assert(func_chain != func);
while (func_chain)
{
// Unlink the removed function from the inheritance chain
if (func_chain->OwnerOverloaded == func)
{
func_chain->OwnerOverloaded = func->OwnerOverloaded;
break;
}
assert(func_chain->OwnerOverloaded && "Removed function not found in inheritance chain");
func_chain = func_chain->OwnerOverloaded->SFunc();
}
}
}
ownedFunctions.clear();
}
void C4ScriptHost::Unreg()
{
// remove from list

View File

@ -54,6 +54,9 @@ public:
std::string Translate(const std::string &text) const;
std::list<C4ScriptHost *> SourceScripts;
StdCopyStrBuf ScriptName; // script name
void UnlinkOwnedFunctions();
protected:
C4ScriptHost();
void Unreg(); // remove from list
@ -83,6 +86,10 @@ protected:
C4LangStringTable *stringTable;
C4Set<C4Property> LocalValues;
C4AulScriptState State; // script state
// list of all functions generated from code in this script host
std::set<C4AulScriptFunc*> ownedFunctions;
friend class C4AulParse;
friend class C4AulProfiler;
friend class C4AulScriptEngine;