- remove all symbols that get linked into the symbol table from the garbage collector.

Symbols are very easy to manage once they are in a symbol table and there's lots of them so this reduces the amount of work the GC needs to do quite considerably.
After cleaning out compile-time-only symbols there will still be more than 2000 left, one for each function and one for each member variable of a class or struct.
This means more than 2000 object that won't need to tracked constantly by the garbage collector.

Note that loose fields which do occur during code generation will be GC'd just as before.
This commit is contained in:
Christoph Oelckers 2017-02-08 14:34:39 +01:00
parent f1b3d60b2f
commit 31223ca180
9 changed files with 64 additions and 116 deletions

View file

@ -301,42 +301,17 @@ DObject::~DObject ()
PClass *type = GetClass(); PClass *type = GetClass();
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
{ {
DObject **probe; if (!(ObjectFlags & (OF_YesReallyDelete|OF_Released)))
if (!(ObjectFlags & OF_YesReallyDelete))
{ {
Printf("Warning: '%s' is freed outside the GC process.\n", Printf("Warning: '%s' is freed outside the GC process.\n",
type != NULL ? type->TypeName.GetChars() : "==some object=="); type != NULL ? type->TypeName.GetChars() : "==some object==");
} }
// Find all pointers that reference this object and NULL them. if (!(ObjectFlags & OF_Released))
StaticPointerSubstitution(this, NULL);
// Now unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{ {
if (*probe == this) // Find all pointers that reference this object and NULL them.
{ StaticPointerSubstitution(this, NULL);
*probe = ObjNext; Release();
if (&ObjNext == GC::SweepPos)
{
GC::SweepPos = probe;
}
break;
}
}
// If it's gray, also unlink it from the gray list.
if (this->IsGray())
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
{
if (*probe == this)
{
*probe = GCNext;
break;
}
}
} }
} }
@ -347,6 +322,41 @@ DObject::~DObject ()
} }
} }
void DObject::Release()
{
DObject **probe;
// Unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{
if (*probe == this)
{
*probe = ObjNext;
if (&ObjNext == GC::SweepPos)
{
GC::SweepPos = probe;
}
break;
}
}
// If it's gray, also unlink it from the gray list.
if (this->IsGray())
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
{
if (*probe == this)
{
*probe = GCNext;
break;
}
}
}
ObjNext = nullptr;
GCNext = nullptr;
ObjectFlags |= OF_Released;
}
//========================================================================== //==========================================================================
// //
// //

View file

@ -468,6 +468,9 @@ public:
Class = NULL; Class = NULL;
} }
// Releases the object from the GC, letting the caller care of any maintenance.
void Release();
// For catching Serialize functions in derived classes // For catching Serialize functions in derived classes
// that don't call their base class. // that don't call their base class.
void CheckIfSerialized () const; void CheckIfSerialized () const;

View file

@ -277,7 +277,9 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
void Mark(DObject **obj) void Mark(DObject **obj)
{ {
DObject *lobj = *obj; DObject *lobj = *obj;
if (lobj != NULL)
assert(lobj == nullptr || !(lobj->ObjectFlags & OF_Released));
if (lobj != nullptr && !(lobj->ObjectFlags & OF_Released))
{ {
if (lobj->ObjectFlags & OF_EuthanizeMe) if (lobj->ObjectFlags & OF_EuthanizeMe)
{ {
@ -551,6 +553,8 @@ void Barrier(DObject *pointing, DObject *pointed)
assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead()));
assert(pointed->IsWhite() && !pointed->IsDead()); assert(pointed->IsWhite() && !pointed->IsDead());
assert(State != GCS_Finalize && State != GCS_Pause); assert(State != GCS_Finalize && State != GCS_Pause);
assert(!(pointed->ObjectFlags & OF_Released)); // if a released object gets here, something must be wrong.
if (pointed->ObjectFlags & OF_Released) return; // don't do anything with non-GC'd objects.
// The invariant only needs to be maintained in the propagate state. // The invariant only needs to be maintained in the propagate state.
if (State == GCS_Propagate) if (State == GCS_Propagate)
{ {

View file

@ -185,18 +185,6 @@ PType::~PType()
{ {
} }
//==========================================================================
//
// PType :: PropagateMark
//
//==========================================================================
size_t PType::PropagateMark()
{
size_t marked = Symbols.MarkSymbols();
return marked + Super::PropagateMark();
}
//========================================================================== //==========================================================================
// //
// PType :: WriteValue // PType :: WriteValue
@ -2413,7 +2401,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags)
if (Symbols.AddSymbol(field) == nullptr) if (Symbols.AddSymbol(field) == nullptr)
{ // name is already in use { // name is already in use
delete field; field->Destroy();
return nullptr; return nullptr;
} }
Fields.Push(field); Fields.Push(field);
@ -2444,18 +2432,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD f
return field; return field;
} }
//==========================================================================
//
// PStruct :: PropagateMark
//
//==========================================================================
size_t PStruct::PropagateMark()
{
GC::MarkArray(Fields);
return Fields.Size() * sizeof(void*) + Super::PropagateMark();
}
//========================================================================== //==========================================================================
// //
// NewStruct // NewStruct

View file

@ -171,8 +171,6 @@ public:
const char *DescriptiveName() const; const char *DescriptiveName() const;
size_t PropagateMark();
static void StaticInit(); static void StaticInit();
}; };
@ -520,8 +518,6 @@ public:
virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddField(FName name, PType *type, DWORD flags=0);
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
size_t PropagateMark();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override; void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;

View file

@ -6558,23 +6558,10 @@ FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition
FxStackVariable::~FxStackVariable() FxStackVariable::~FxStackVariable()
{ {
// Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap.
membervar->ObjectFlags |= OF_YesReallyDelete; membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar; delete membervar;
} }
//==========================================================================
//
//
//==========================================================================
void FxStackVariable::ReplaceField(PField *newfield)
{
membervar->ObjectFlags |= OF_YesReallyDelete;
delete membervar;
membervar = newfield;
}
//========================================================================== //==========================================================================
// //
// //

View file

@ -1417,7 +1417,6 @@ class FxStackVariable : public FxMemberBase
public: public:
FxStackVariable(PType *type, int offset, const FScriptPosition&); FxStackVariable(PType *type, int offset, const FScriptPosition&);
~FxStackVariable(); ~FxStackVariable();
void ReplaceField(PField *newfield);
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
bool RequestAddress(FCompileContext &ctx, bool *writable); bool RequestAddress(FCompileContext &ctx, bool *writable);
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);

View file

@ -149,34 +149,19 @@ PSymbolTable::~PSymbolTable ()
//========================================================================== //==========================================================================
// //
// // this must explicitly delete all content because the symbols have
// // been released from the GC.
//==========================================================================
size_t PSymbolTable::MarkSymbols()
{
size_t count = 0;
MapType::Iterator it(Symbols);
MapType::Pair *pair;
while (it.NextPair(pair))
{
GC::Mark(pair->Value);
count++;
}
return count * sizeof(*pair);
}
//==========================================================================
//
//
// //
//========================================================================== //==========================================================================
void PSymbolTable::ReleaseSymbols() void PSymbolTable::ReleaseSymbols()
{ {
// The GC will take care of deleting the symbols. We just need to auto it = GetIterator();
// clear our references to them. MapType::Pair *pair;
while (it.NextPair(pair))
{
delete pair->Value;
}
Symbols.Clear(); Symbols.Clear();
} }
@ -243,6 +228,7 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
return nullptr; return nullptr;
} }
Symbols.Insert(sym->SymbolName, sym); Symbols.Insert(sym->SymbolName, sym);
sym->Release(); // no more GC, please!
return sym; return sym;
} }
@ -257,6 +243,7 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym)
auto mysym = Symbols.CheckKey(sym->SymbolName); auto mysym = Symbols.CheckKey(sym->SymbolName);
if (mysym == nullptr || *mysym != sym) return; if (mysym == nullptr || *mysym != sym) return;
Symbols.Remove(sym->SymbolName); Symbols.Remove(sym->SymbolName);
delete sym;
} }
//========================================================================== //==========================================================================
@ -265,20 +252,20 @@ void PSymbolTable::RemoveSymbol(PSymbol *sym)
// //
//========================================================================== //==========================================================================
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) void PSymbolTable::ReplaceSymbol(PSymbol *newsym)
{ {
// If a symbol with a matching name exists, take its place and return it. // If a symbol with a matching name exists, take its place and return it.
PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName);
if (symslot != nullptr) if (symslot != nullptr)
{ {
PSymbol *oldsym = *symslot; PSymbol *oldsym = *symslot;
delete oldsym;
*symslot = newsym; *symslot = newsym;
return oldsym;
} }
// Else, just insert normally and return nullptr since there was no // Else, just insert normally and return nullptr since there was no
// symbol to replace. // symbol to replace.
newsym->Release(); // no more GC, please!
Symbols.Insert(newsym->SymbolName, newsym); Symbols.Insert(newsym->SymbolName, newsym);
return nullptr;
} }
//========================================================================== //==========================================================================
@ -306,18 +293,6 @@ PNamespace::PNamespace(int filenum, PNamespace *parent)
// //
//========================================================================== //==========================================================================
size_t PNamespace::PropagateMark()
{
GC::Mark(Parent);
return Symbols.MarkSymbols() + 1;
}
//==========================================================================
//
//
//
//==========================================================================
FNamespaceManager::FNamespaceManager() FNamespaceManager::FNamespaceManager()
{ {
GlobalNamespace = nullptr; GlobalNamespace = nullptr;
@ -370,6 +345,7 @@ size_t FNamespaceManager::MarkSymbols()
void FNamespaceManager::ReleaseSymbols() void FNamespaceManager::ReleaseSymbols()
{ {
RemoveSymbols();
GlobalNamespace = nullptr; GlobalNamespace = nullptr;
AllNamespaces.Clear(); AllNamespaces.Clear();
} }

View file

@ -192,8 +192,6 @@ struct PSymbolTable
PSymbolTable(PSymbolTable *parent); PSymbolTable(PSymbolTable *parent);
~PSymbolTable(); ~PSymbolTable();
size_t MarkSymbols();
// Sets the table to use for searches if this one doesn't contain the // Sets the table to use for searches if this one doesn't contain the
// requested symbol. // requested symbol.
void SetParentTable (PSymbolTable *parent); void SetParentTable (PSymbolTable *parent);
@ -218,7 +216,7 @@ struct PSymbolTable
// Similar to AddSymbol but always succeeds. Returns the symbol that used // Similar to AddSymbol but always succeeds. Returns the symbol that used
// to be in the table with this name, if any. // to be in the table with this name, if any.
PSymbol *ReplaceSymbol(PSymbol *sym); void ReplaceSymbol(PSymbol *sym);
void RemoveSymbol(PSymbol *sym); void RemoveSymbol(PSymbol *sym);
@ -255,7 +253,6 @@ public:
PNamespace() {} PNamespace() {}
PNamespace(int filenum, PNamespace *parent); PNamespace(int filenum, PNamespace *parent);
size_t PropagateMark();
}; };
struct FNamespaceManager struct FNamespaceManager