- activated the garbage collector

This finally gets rid of all static storage for actors - so no more indices ever! :)
This commit is contained in:
Christoph Oelckers 2021-12-06 17:00:15 +01:00
parent 0dd756fa32
commit 8ee5d1b0d7
18 changed files with 80 additions and 88 deletions

View file

@ -195,6 +195,7 @@ static DObject **SweepList(DObject **p, size_t count, size_t *finalize_count)
// However, this can happen during deletion of the thinker list while cleaning up // However, this can happen during deletion of the thinker list while cleaning up
// from a savegame error so we can't assume that any thinker that gets here is an error. // from a savegame error so we can't assume that any thinker that gets here is an error.
assert(!curr->IsKindOf("CoreActor"));
curr->Destroy(); curr->Destroy();
} }

View file

@ -186,6 +186,8 @@ class TObjPtr
public: public:
TObjPtr() = default; TObjPtr() = default;
TObjPtr(const TObjPtr<T> &q) = delete;
TObjPtr(T q) noexcept TObjPtr(T q) noexcept
: pp(q) : pp(q)
{ {

View file

@ -32,7 +32,6 @@
** **
*/ */
#include <deque>
#include "build.h" #include "build.h"
#include "coreactor.h" #include "coreactor.h"
#include "gamefuncs.h" #include "gamefuncs.h"
@ -40,7 +39,6 @@
// Doubly linked ring list of Actors // Doubly linked ring list of Actors
std::deque<DCoreActor*> freeList; // only needed until we can get rid of the sprite array.
ActorStatList statList[MAXSTATUS]; ActorStatList statList[MAXSTATUS];
//========================================================================== //==========================================================================
@ -100,8 +98,8 @@ static void AddStatTail(DCoreActor* actor, int statnum)
assert(ValidateStatList(statnum)); assert(ValidateStatList(statnum));
actor->s().statnum = statnum; actor->s().statnum = statnum;
actor->link_stat = statnum; actor->link_stat = statnum;
//GC::WriteBarrier(tail); GC::WriteBarrier(actor);
//GC::WriteBarrier(actor); GC::WriteBarrier(tail);
} }
//========================================================================== //==========================================================================
@ -124,8 +122,8 @@ static void AddStatHead(DCoreActor* actor, int statnum)
statList[statnum].firstEntry = actor; statList[statnum].firstEntry = actor;
actor->s().statnum = statnum; actor->s().statnum = statnum;
actor->link_stat = statnum; actor->link_stat = statnum;
//GC::WriteBarrier(head); GC::WriteBarrier(actor);
//GC::WriteBarrier(actor); GC::WriteBarrier(head);
} }
@ -155,10 +153,8 @@ static void RemoveActorStat(DCoreActor* actor)
actor->nextStat = actor->prevStat = nullptr; actor->nextStat = actor->prevStat = nullptr;
actor->s().statnum = MAXSTATUS; actor->s().statnum = MAXSTATUS;
actor->link_stat = MAXSTATUS; actor->link_stat = MAXSTATUS;
/* GC::WriteBarrier(prev);
GC::WriteBarrier(prev, next); GC::WriteBarrier(next);
GC::WriteBarrier(next, prev);
*/
} }
//========================================================================== //==========================================================================
@ -239,8 +235,8 @@ static void AddSectTail(DCoreActor *actor, sectortype* sect)
assert(ValidateSectList(sect)); assert(ValidateSectList(sect));
actor->s().setsector(sect); actor->s().setsector(sect);
actor->link_sector = sect; actor->link_sector = sect;
//GC::WriteBarrier(tail); GC::WriteBarrier(actor);
//GC::WriteBarrier(actor); GC::WriteBarrier(tail);
} }
//========================================================================== //==========================================================================
@ -263,8 +259,8 @@ static void AddSectHead(DCoreActor *actor, sectortype* sect)
assert(ValidateSectList(sect)); assert(ValidateSectList(sect));
actor->s().sectnum = sectnum(sect); actor->s().sectnum = sectnum(sect);
actor->link_sector = sect; actor->link_sector = sect;
//GC::WriteBarrier(head); GC::WriteBarrier(actor);
//GC::WriteBarrier(actor); GC::WriteBarrier(head);
} }
//========================================================================== //==========================================================================
@ -299,10 +295,8 @@ static void RemoveActorSect(DCoreActor* actor)
actor->nextSect = actor->prevSect = nullptr; actor->nextSect = actor->prevSect = nullptr;
actor->s().setsector(nullptr); actor->s().setsector(nullptr);
actor->link_sector = nullptr; actor->link_sector = nullptr;
/* GC::WriteBarrier(prev);
GC::WriteBarrier(prev, next); GC::WriteBarrier(next);
GC::WriteBarrier(next, prev);
*/
} }
//========================================================================== //==========================================================================
@ -344,16 +338,12 @@ void ChangeActorSect(DCoreActor* actor, sectortype* sect, bool tail)
// //
//========================================================================== //==========================================================================
DCoreActor* InsertActor(sectortype* sector, int stat, bool tail) DCoreActor* InsertActor(PClass* type, sectortype* sector, int stat, bool tail)
{ {
if (freeList.empty()) assert(type->IsDescendantOf(RUNTIME_CLASS(DCoreActor)));
{
I_Error("Out of sprites!"); // we cannot deal with this - and most of the calling code never checks...
return nullptr;
}
auto actor = freeList.back(); auto actor = static_cast<DCoreActor*>(type->CreateNew());
freeList.pop_back(); GC::WriteBarrier(actor);
spritetype* pSprite = &actor->s(); spritetype* pSprite = &actor->s();
pSprite->clear(); pSprite->clear();
@ -372,27 +362,23 @@ DCoreActor* InsertActor(sectortype* sector, int stat, bool tail)
// //
//========================================================================== //==========================================================================
int DeleteActor(DCoreActor* actor) void DCoreActor::OnDestroy()
{ {
auto sp = &actor->s(); assert(spr.statnum >= 0 && spr.statnum < MAXSTATUS);
assert(sp->statnum >= 0 && sp->statnum < MAXSTATUS);
int stat = actor->link_stat; int stat = link_stat;
RemoveActorStat(actor); RemoveActorStat(this);
auto sect = actor->link_sector; auto sect = link_sector;
if (sect) if (sect)
{ {
RemoveActorSect(actor); RemoveActorSect(this);
} }
else else
{ {
assert(actor->prevSect == nullptr && actor->nextSect == nullptr); assert(prevSect == nullptr && nextSect == nullptr);
} }
Numsprites--; Numsprites--;
actor->ClearContent();
freeList.push_front(actor);
return 0;
} }
//========================================================================== //==========================================================================
@ -401,10 +387,19 @@ int DeleteActor(DCoreActor* actor)
// we can use real DObject life cycle management. // we can use real DObject life cycle management.
// //
//========================================================================== //==========================================================================
static DCoreActor* actorArray[16384];
void InitSpriteLists() void InitSpriteLists()
{ {
// Do not mass-destroy from the iterator. This may fail if destroying one actor results in further destructions.
TArray<DCoreActor*> allActors;
TSpriteIterator<DCoreActor> it;
while (auto actor = it.Next())
allActors.Push(actor);
for (auto& act : allActors)
{
if (!(act->ObjectFlags & OF_EuthanizeMe))
act->Destroy();
}
for (auto& stat : statList) for (auto& stat : statList)
{ {
stat.firstEntry = stat.lastEntry = nullptr; stat.firstEntry = stat.lastEntry = nullptr;
@ -413,12 +408,6 @@ void InitSpriteLists()
{ {
sect.firstEntry = sect.lastEntry = nullptr; sect.firstEntry = sect.lastEntry = nullptr;
} }
freeList.clear();
for(auto& actor : actorArray)
{
actor->ClearContent();
freeList.push_front(actor);
}
Numsprites = 0; Numsprites = 0;
} }
@ -457,16 +446,6 @@ size_t DCoreActor::PropagateMark()
GC::Mark(nextStat); GC::Mark(nextStat);
GC::Mark(prevSect); GC::Mark(prevSect);
GC::Mark(nextSect); GC::Mark(nextSect);
return 4 + Super::PropagateMark(); return Super::PropagateMark();
} }
void SetupActors(PClass* clstype)
{
// this is temporary until we have added proper tracking to all pointers in the games.
// Until then we have to keep a static array of actors to avoid stale references to deallocated memory.
for (int i = 0; i < 16384; i++)
{
actorArray[i] = static_cast<DCoreActor*>(clstype->CreateNew());
actorArray[i]->Release(); // no GC for this static array.
}
}

View file

@ -35,6 +35,8 @@ public:
spr = {}; spr = {};
} }
virtual void BeginPlay() {}
void OnDestroy() override;
size_t PropagateMark() override; size_t PropagateMark() override;
bool exists() const bool exists() const
@ -338,12 +340,10 @@ public:
using CoreSectIterator = TSectIterator<DCoreActor>; using CoreSectIterator = TSectIterator<DCoreActor>;
DCoreActor* InsertActor(sectortype* sector, int stat, bool forcetail = false); DCoreActor* InsertActor(PClass* type, sectortype* sector, int stat, bool forcetail = false);
int DeleteActor(DCoreActor* actor);
void ChangeActorSect(DCoreActor* actor, sectortype* sector, bool forcetail = false); void ChangeActorSect(DCoreActor* actor, sectortype* sector, bool forcetail = false);
int ChangeActorStat(DCoreActor* actor, int nStatus, bool forcetail = false); int ChangeActorStat(DCoreActor* actor, int nStatus, bool forcetail = false);
void InitSpriteLists(); void InitSpriteLists();
void SetupActors(PClass* clstype);
void SetActorZ(DCoreActor* actor, const vec3_t* newpos); void SetActorZ(DCoreActor* actor, const vec3_t* newpos);

View file

@ -373,6 +373,19 @@ static void GameTicker()
break; break;
} }
GC::CheckGC();
// Do some more aggressive GC maintenance when the game ticker is inactive.
if ((gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) || paused)
{
size_t ac = max<size_t>(10, GC::AllocCount);
for (size_t i = 0; i < ac; i++)
{
if (!GC::CheckGC()) break;
}
}
} }

View file

@ -529,6 +529,11 @@ void setWallSectors()
void MarkMap() void MarkMap()
{ {
for (auto& stat : statList)
{
GC::Mark(stat.firstEntry);
GC::Mark(stat.lastEntry);
}
for (auto& sect : sectors()) for (auto& sect : sectors())
{ {
GC::Mark(sect.firstEntry); GC::Mark(sect.firstEntry);

View file

@ -75,7 +75,7 @@ size_t DBloodActor::PropagateMark()
{ {
condition[0].Mark(); condition[0].Mark();
condition[1].Mark(); condition[1].Mark();
return 2 + Super::PropagateMark(); return Super::PropagateMark();
} }
static void markgcroots() static void markgcroots()
@ -535,7 +535,6 @@ void GameInterface::loadPalette(void)
void GameInterface::app_init() void GameInterface::app_init()
{ {
SetupActors(RUNTIME_CLASS(DBloodActor));
GC::AddMarkerFunc(markgcroots); GC::AddMarkerFunc(markgcroots);
InitCheats(); InitCheats();
memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS)); memcpy(&gGameOptions, &gSingleGameOptions, sizeof(GAMEOPTIONS));

View file

@ -40,7 +40,7 @@ BEGIN_BLD_NS
DBloodActor* InsertSprite(sectortype* pSector, int nStat) DBloodActor* InsertSprite(sectortype* pSector, int nStat)
{ {
auto act = static_cast<DBloodActor*>(::InsertActor(pSector, nStat)); auto act = static_cast<DBloodActor*>(::InsertActor(RUNTIME_CLASS(DBloodActor), pSector, nStat));
auto pSprite = &act->s(); auto pSprite = &act->s();
pSprite->cstat = 128; pSprite->cstat = 128;
pSprite->clipdist = 32; pSprite->clipdist = 32;
@ -58,7 +58,7 @@ int DeleteSprite(DBloodActor* actor)
for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == actor) ctrl.qavScene.initiator = nullptr; for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == actor) ctrl.qavScene.initiator = nullptr;
#endif #endif
::DeleteActor(actor); actor->Destroy();
return 0; return 0;
} }

View file

@ -78,7 +78,7 @@ void deletesprite(DDukeActor *const actor)
S_StopSound(actor->s->lotag, actor); S_StopSound(actor->s->lotag, actor);
else else
S_RelinkActorSound(actor, nullptr); S_RelinkActorSound(actor, nullptr);
::DeleteActor(actor); actor->Destroy();
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -67,7 +67,7 @@ size_t DDukeActor::PropagateMark()
{ {
var.Mark(); var.Mark();
} }
return uservars.Size() + Super::PropagateMark(); return Super::PropagateMark();
} }
static void markgcroots() static void markgcroots()
@ -334,7 +334,6 @@ int GameInterface::GetCurrentSkill()
void GameInterface::app_init() void GameInterface::app_init()
{ {
SetupActors(RUNTIME_CLASS(DDukeActor));
GC::AddMarkerFunc(markgcroots); GC::AddMarkerFunc(markgcroots);
if (isRR()) C_SetNotifyFontScale(0.5); if (isRR()) C_SetNotifyFontScale(0.5);

View file

@ -947,7 +947,7 @@ static TArray<DDukeActor*> spawnactors(SpawnSpriteDef& sprites)
continue; continue;
} }
auto sprt = &sprites.sprites[i]; auto sprt = &sprites.sprites[i];
auto actor = static_cast<DDukeActor*>(InsertActor(sprt->sector(), sprt->statnum)); auto actor = static_cast<DDukeActor*>(InsertActor(RUNTIME_CLASS(DDukeActor), sprt->sector(), sprt->statnum));
spawns[j++] = actor; spawns[j++] = actor;
actor->spr = sprites.sprites[i]; actor->spr = sprites.sprites[i];
actor->s = &actor->spr; actor->s = &actor->spr;

View file

@ -53,7 +53,7 @@ DDukeActor* EGS(sectortype* whatsectp, int s_x, int s_y, int s_z, int s_pn, int8
{ {
// sector pointer must be strictly validated here or the engine will crash. // sector pointer must be strictly validated here or the engine will crash.
if (whatsectp == nullptr || !validSectorIndex(sectnum(whatsectp))) return nullptr; if (whatsectp == nullptr || !validSectorIndex(sectnum(whatsectp))) return nullptr;
auto act = static_cast<DDukeActor*>(::InsertActor(whatsectp, s_ss)); auto act = static_cast<DDukeActor*>(::InsertActor(RUNTIME_CLASS(DDukeActor), whatsectp, s_ss));
if (act == nullptr) return nullptr; if (act == nullptr) return nullptr;
act->s = &act->spr; act->s = &act->spr;

View file

@ -74,23 +74,19 @@ size_t MarkRunlist();
static void markgcroots() static void markgcroots()
{ {
size_t num = MarkMove(); MarkBullets();
num += MarkBullets(); MarkInput();
num += MarkInput(); MarkItems();
num += MarkItems(); MarkLighting();
num += MarkLighting(); MarkObjects();
num += MarkObjects(); MarkPlayers();
num += MarkPlayers(); MarkQueen();
num += MarkQueen(); MarkRa();
num += MarkRa(); MarkSnake();
num += MarkSnake(); MarkRunlist();
num += MarkRunlist();
GC::Mark(bestTarget); GC::Mark(bestTarget);
GC::Mark(pSpiritSprite); GC::Mark(pSpiritSprite);
num += 2;
Printf("%d objects marked\n", num);
} }
static MapRecord* NextMap; static MapRecord* NextMap;
@ -502,7 +498,6 @@ static void SetTileNames()
void GameInterface::app_init() void GameInterface::app_init()
{ {
SetupActors(RUNTIME_CLASS(DExhumedActor));
GC::AddMarkerFunc(markgcroots); GC::AddMarkerFunc(markgcroots);
@ -544,7 +539,7 @@ void DeleteActor(DExhumedActor* actor)
bestTarget = nullptr; bestTarget = nullptr;
} }
::DeleteActor(actor); actor->Destroy();
} }

View file

@ -485,7 +485,7 @@ int GetActorHeight(DExhumedActor* actor)
DExhumedActor* insertActor(sectortype* s, int st) DExhumedActor* insertActor(sectortype* s, int st)
{ {
return static_cast<DExhumedActor*>(::InsertActor(s, st)); return static_cast<DExhumedActor*>(::InsertActor(RUNTIME_CLASS(DExhumedActor), s, st));
} }

View file

@ -1279,7 +1279,7 @@ PostDraw(void)
while (auto actor = it.Next()) while (auto actor = it.Next())
{ {
actor->clearUser(); actor->clearUser();
::DeleteActor(actor); actor->Destroy();
} }
} }

View file

@ -233,7 +233,6 @@ void GameInterface::LoadGameTextures()
void GameInterface::app_init() void GameInterface::app_init()
{ {
SetupActors(RUNTIME_CLASS(DSWActor));
GC::AddMarkerFunc(markgcroots); GC::AddMarkerFunc(markgcroots);
GameTicRate = TICS_PER_SEC / synctics; GameTicRate = TICS_PER_SEC / synctics;

View file

@ -56,7 +56,7 @@ bool FAF_DebugView = false;
DSWActor* insertActor(sectortype* sect, int statnum) DSWActor* insertActor(sectortype* sect, int statnum)
{ {
auto pActor = static_cast<DSWActor*>(::InsertActor(sect, statnum)); auto pActor = static_cast<DSWActor*>(::InsertActor(RUNTIME_CLASS(DSWActor), sect, statnum));
auto pSprite = &pActor->s(); auto pSprite = &pActor->s();
pSprite->x = pSprite->y = pSprite->z = 0; pSprite->x = pSprite->y = pSprite->z = 0;

View file

@ -770,7 +770,7 @@ void KillActor(DSWActor* actor)
FVector3 pos = GetSoundPos(&actor->s().pos); FVector3 pos = GetSoundPos(&actor->s().pos);
soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos); soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos);
::DeleteActor(actor); actor->Destroy();
// shred your garbage // shred your garbage
sp->clear(); sp->clear();