Store type together with pointers to allow safe substitution
This commit is contained in:
parent
6b7065899d
commit
e85ec240bf
5 changed files with 208 additions and 166 deletions
|
|
@ -363,54 +363,49 @@ size_t DObject::PropagateMark()
|
|||
const PClass *info = GetClass();
|
||||
if (!PClass::bShutdown)
|
||||
{
|
||||
const size_t *offsets = info->FlatPointers;
|
||||
if (offsets == NULL)
|
||||
if (info->FlatPointers == nullptr)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildFlatPointers();
|
||||
offsets = info->FlatPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
GC::Mark((DObject **)((uint8_t *)this + *offsets));
|
||||
offsets++;
|
||||
info->BuildFlatPointers();
|
||||
assert(info->FlatPointers);
|
||||
}
|
||||
|
||||
offsets = info->ArrayPointers;
|
||||
if (offsets == NULL)
|
||||
for(size_t i = 0; i < info->FlatPointersSize; i++)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildArrayPointers();
|
||||
offsets = info->ArrayPointers;
|
||||
GC::Mark((DObject **)((uint8_t *)this + info->FlatPointers[i].first));
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
|
||||
if (info->ArrayPointers == nullptr)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
|
||||
info->BuildArrayPointers();
|
||||
assert(info->ArrayPointers);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < info->ArrayPointersSize; i++)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((uint8_t *)this + info->ArrayPointers[i].first);
|
||||
for (auto &p : *aray)
|
||||
{
|
||||
GC::Mark(&p);
|
||||
}
|
||||
offsets++;
|
||||
}
|
||||
|
||||
if (info->MapPointers == nullptr)
|
||||
{
|
||||
const std::pair<size_t,PType *> *maps = info->MapPointers;
|
||||
if (maps == NULL)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildMapPointers();
|
||||
maps = info->MapPointers;
|
||||
}
|
||||
while (maps->first != ~(size_t)0)
|
||||
{
|
||||
if(maps->second->RegType == REGT_STRING)
|
||||
{ // FString,DObject*
|
||||
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + maps->first));
|
||||
}
|
||||
else
|
||||
{ // uint32_t,DObject*
|
||||
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + maps->first));
|
||||
}
|
||||
maps++;
|
||||
}
|
||||
info->BuildMapPointers();
|
||||
assert(info->MapPointers);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < info->MapPointersSize; i++)
|
||||
{
|
||||
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
|
||||
if(type->KeyType->RegType == REGT_STRING)
|
||||
{ // FString,DObject*
|
||||
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
|
||||
}
|
||||
else
|
||||
{ // uint32_t,DObject*
|
||||
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
|
||||
}
|
||||
}
|
||||
return info->Size;
|
||||
}
|
||||
|
|
@ -423,35 +418,51 @@ size_t DObject::PropagateMark()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
template<typename M>
|
||||
static void MapPointerSubstitution(M *map, size_t &changed, DObject *old, DObject *notOld)
|
||||
{
|
||||
TMapIterator<typename M::KeyType, DObject*> it(*map);
|
||||
typename M::Pair * p;
|
||||
while(it.NextPair(p))
|
||||
{
|
||||
if (p->Value == old)
|
||||
{
|
||||
p->Value = notOld;
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
|
||||
{
|
||||
const PClass *info = GetClass();
|
||||
const size_t *offsets = info->FlatPointers;
|
||||
size_t changed = 0;
|
||||
if (offsets == NULL)
|
||||
if (info->FlatPointers == nullptr)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildFlatPointers();
|
||||
offsets = info->FlatPointers;
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
{
|
||||
if (*(DObject **)((uint8_t *)this + *offsets) == old)
|
||||
{
|
||||
*(DObject **)((uint8_t *)this + *offsets) = notOld;
|
||||
changed++;
|
||||
}
|
||||
offsets++;
|
||||
info->BuildFlatPointers();
|
||||
assert(info->FlatPointers);
|
||||
}
|
||||
|
||||
offsets = info->ArrayPointers;
|
||||
if (offsets == NULL)
|
||||
for(size_t i = 0; i < info->FlatPointersSize; i++)
|
||||
{
|
||||
const_cast<PClass *>(info)->BuildArrayPointers();
|
||||
offsets = info->ArrayPointers;
|
||||
size_t offset = info->FlatPointers[i].first;
|
||||
|
||||
if (*(DObject **)((uint8_t *)this + offset) == old)
|
||||
{
|
||||
*(DObject **)((uint8_t *)this + offset) = notOld;
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
while (*offsets != ~(size_t)0)
|
||||
|
||||
if (info->ArrayPointers == nullptr)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
|
||||
info->BuildArrayPointers();
|
||||
assert(info->ArrayPointers);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < info->ArrayPointersSize; i++)
|
||||
{
|
||||
auto aray = (TArray<DObject*>*)((uint8_t *)this + info->ArrayPointers[i].first);
|
||||
for (auto &p : *aray)
|
||||
{
|
||||
if (p == old)
|
||||
|
|
@ -460,9 +471,26 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
|
|||
changed++;
|
||||
}
|
||||
}
|
||||
offsets++;
|
||||
}
|
||||
|
||||
if (info->MapPointers == nullptr)
|
||||
{
|
||||
info->BuildMapPointers();
|
||||
assert(info->MapPointers);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < info->MapPointersSize; i++)
|
||||
{
|
||||
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
|
||||
if(type->KeyType->RegType == REGT_STRING)
|
||||
{ // FString,DObject*
|
||||
MapPointerSubstitution((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld);
|
||||
}
|
||||
else
|
||||
{ // uint32_t,DObject*
|
||||
MapPointerSubstitution((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld);
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,9 +80,7 @@ DEFINE_GLOBAL(WP_NOCHANGE);
|
|||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
// A harmless non-nullptr FlatPointer for classes without pointers.
|
||||
static const size_t TheEnd = ~(size_t)0;
|
||||
|
||||
static const std::pair<size_t,PType *> TheMapEnd = {~(size_t)0 , nullptr};
|
||||
static const std::pair<size_t,PType *> TheEnd = {~(size_t)0 , nullptr};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
@ -768,75 +766,81 @@ PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::BuildFlatPointers ()
|
||||
void PClass::BuildFlatPointers() const
|
||||
{
|
||||
using pairType = std::pair<size_t, PObjectPointer *>;
|
||||
|
||||
if (FlatPointers != nullptr)
|
||||
{ // Already built: Do nothing.
|
||||
return;
|
||||
}
|
||||
else if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
|
||||
if (Pointers == nullptr)
|
||||
{ // No pointers: Make FlatPointers a harmless non-nullptr.
|
||||
FlatPointers = &TheEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
FlatPointers = Pointers;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentClass->BuildFlatPointers ();
|
||||
|
||||
TArray<size_t> ScriptPointers;
|
||||
|
||||
// Collect all pointers in scripted fields. These are not part of the Pointers list.
|
||||
for (auto field : Fields)
|
||||
TArray<pairType> NativePointers;
|
||||
if (Pointers != nullptr)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native))
|
||||
for (size_t i = 0; Pointers[i] != ~(size_t)0; i++)
|
||||
{
|
||||
field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers);
|
||||
NativePointers.Push({Pointers[i], nullptr}); // native pointers have a null type
|
||||
}
|
||||
}
|
||||
|
||||
if (Pointers == nullptr && ScriptPointers.Size() == 0)
|
||||
{ // No new pointers: Just use the same FlatPointers as the parent.
|
||||
FlatPointers = ParentClass->FlatPointers;
|
||||
if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject): FlatPointers is the same as Pointers.
|
||||
if (NativePointers.Size() == 0)
|
||||
{ // No pointers: Make FlatPointers a harmless non-nullptr.
|
||||
FlatPointers = (pairType*)(&TheEnd);
|
||||
FlatPointersSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * NativePointers.Size());
|
||||
memcpy(flat, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
|
||||
|
||||
FlatPointers = flat;
|
||||
FlatPointersSize = NativePointers.Size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
int numPointers, numSuperPointers;
|
||||
{
|
||||
ParentClass->BuildFlatPointers();
|
||||
|
||||
if (Pointers != nullptr)
|
||||
TArray<pairType> ScriptPointers;
|
||||
|
||||
// Collect all pointers in scripted fields. These are not part of the Pointers list.
|
||||
for (auto field : Fields)
|
||||
{
|
||||
// Count pointers defined by this class.
|
||||
for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++)
|
||||
if (!(field->Flags & VARF_Native))
|
||||
{
|
||||
field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers);
|
||||
}
|
||||
}
|
||||
else numPointers = 0;
|
||||
|
||||
// Count pointers defined by superclasses.
|
||||
for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
|
||||
{ }
|
||||
if (NativePointers.Size() == 0 && ScriptPointers.Size() == 0)
|
||||
{ // No new pointers: Just use the same FlatPointers as the parent.
|
||||
FlatPointers = ParentClass->FlatPointers;
|
||||
FlatPointersSize = ParentClass->FlatPointersSize;
|
||||
}
|
||||
else
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
// Concatenate them into a new array
|
||||
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size()));
|
||||
|
||||
// Concatenate them into a new array
|
||||
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1));
|
||||
if (numSuperPointers > 0)
|
||||
{
|
||||
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
|
||||
if (ParentClass->FlatPointersSize > 0)
|
||||
{
|
||||
memcpy (flat, ParentClass->FlatPointers, sizeof(pairType) * ParentClass->FlatPointersSize);
|
||||
}
|
||||
if (NativePointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + ParentClass->FlatPointersSize, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
|
||||
}
|
||||
if (ScriptPointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + ParentClass->FlatPointersSize + NativePointers.Size(), &ScriptPointers[0], sizeof(pairType) * ScriptPointers.Size());
|
||||
}
|
||||
FlatPointers = flat;
|
||||
FlatPointersSize = ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size();
|
||||
}
|
||||
if (numPointers > 0)
|
||||
{
|
||||
memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers);
|
||||
}
|
||||
if (ScriptPointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
|
||||
}
|
||||
flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0;
|
||||
FlatPointers = flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -849,21 +853,24 @@ void PClass::BuildFlatPointers ()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::BuildArrayPointers()
|
||||
void PClass::BuildArrayPointers() const
|
||||
{
|
||||
using pairType = std::pair<size_t, PDynArray *>;
|
||||
|
||||
if (ArrayPointers != nullptr)
|
||||
{ // Already built: Do nothing.
|
||||
return;
|
||||
}
|
||||
else if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
|
||||
ArrayPointers = &TheEnd;
|
||||
{ // No parent (i.e. DObject): Make ArrayPointers a harmless non-nullptr.
|
||||
ArrayPointers = (pairType*)(&TheEnd);
|
||||
ArrayPointersSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentClass->BuildArrayPointers();
|
||||
|
||||
TArray<size_t> ScriptPointers;
|
||||
TArray<pairType> ScriptPointers;
|
||||
|
||||
// Collect all arrays to pointers in scripted fields.
|
||||
for (auto field : Fields)
|
||||
|
|
@ -877,28 +884,24 @@ void PClass::BuildArrayPointers()
|
|||
if (ScriptPointers.Size() == 0)
|
||||
{ // No new pointers: Just use the same ArrayPointers as the parent.
|
||||
ArrayPointers = ParentClass->ArrayPointers;
|
||||
ArrayPointersSize = ParentClass->ArrayPointersSize;
|
||||
}
|
||||
else
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
int numSuperPointers;
|
||||
|
||||
// Count pointers defined by superclasses.
|
||||
for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
|
||||
{
|
||||
}
|
||||
|
||||
{ // New pointers: Create a new ArrayPointers array and add them.
|
||||
// Concatenate them into a new array
|
||||
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1));
|
||||
if (numSuperPointers > 0)
|
||||
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->ArrayPointersSize + ScriptPointers.Size()));
|
||||
if (ParentClass->ArrayPointersSize > 0)
|
||||
{
|
||||
memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers);
|
||||
memcpy(flat, ParentClass->ArrayPointers, sizeof(pairType) * ParentClass->ArrayPointersSize);
|
||||
}
|
||||
|
||||
if (ScriptPointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
|
||||
memcpy(flat + ParentClass->ArrayPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
|
||||
}
|
||||
flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0;
|
||||
|
||||
ArrayPointers = flat;
|
||||
ArrayPointersSize = ParentClass->ArrayPointersSize + ScriptPointers.Size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -911,21 +914,24 @@ void PClass::BuildArrayPointers()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::BuildMapPointers()
|
||||
void PClass::BuildMapPointers() const
|
||||
{
|
||||
using pairType = std::pair<size_t, PMap *>;
|
||||
|
||||
if (MapPointers != nullptr)
|
||||
{ // Already built: Do nothing.
|
||||
return;
|
||||
}
|
||||
else if (ParentClass == nullptr)
|
||||
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
|
||||
MapPointers = &TheMapEnd;
|
||||
{ // No parent (i.e. DObject): Make MapPointers a harmless non-nullptr.
|
||||
MapPointers = (pairType*)(&TheEnd);
|
||||
MapPointersSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentClass->BuildMapPointers();
|
||||
|
||||
TArray<std::pair<size_t,PType *>> ScriptPointers;
|
||||
TArray<pairType> ScriptPointers;
|
||||
|
||||
// Collect all arrays to pointers in scripted fields.
|
||||
for (auto field : Fields)
|
||||
|
|
@ -939,28 +945,23 @@ void PClass::BuildMapPointers()
|
|||
if (ScriptPointers.Size() == 0)
|
||||
{ // No new pointers: Just use the same ArrayPointers as the parent.
|
||||
MapPointers = ParentClass->MapPointers;
|
||||
MapPointersSize = ParentClass->MapPointersSize;
|
||||
}
|
||||
else
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
int numSuperPointers;
|
||||
|
||||
// Count pointers defined by superclasses.
|
||||
for (numSuperPointers = 0; ParentClass->MapPointers[numSuperPointers].first != ~(size_t)0; numSuperPointers++)
|
||||
{
|
||||
}
|
||||
|
||||
{ // New pointers: Create a new FlatPointers array and add them.
|
||||
// Concatenate them into a new array
|
||||
std::pair<size_t,PType *> *flat = (std::pair<size_t,PType *>*)ClassDataAllocator.Alloc(sizeof(std::pair<size_t,PType *>) * (numSuperPointers + ScriptPointers.Size() + 1));
|
||||
if (numSuperPointers > 0)
|
||||
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->MapPointersSize + ScriptPointers.Size()));
|
||||
if (ParentClass->MapPointersSize > 0)
|
||||
{
|
||||
memcpy(flat, ParentClass->MapPointers, sizeof(std::pair<size_t,PType *>)*numSuperPointers);
|
||||
memcpy(flat, ParentClass->MapPointers, sizeof(pairType) * ParentClass->MapPointersSize);
|
||||
}
|
||||
|
||||
if (ScriptPointers.Size() > 0)
|
||||
{
|
||||
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(std::pair<size_t,PType *>) * ScriptPointers.Size());
|
||||
memcpy(flat + ParentClass->MapPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
|
||||
}
|
||||
flat[numSuperPointers + ScriptPointers.Size()] = TheMapEnd;
|
||||
MapPointers = flat;
|
||||
MapPointersSize = ParentClass->MapPointersSize + ScriptPointers.Size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ class PClassType;
|
|||
struct FNamespaceManager;
|
||||
class PSymbol;
|
||||
class PField;
|
||||
class PObjectPointer;
|
||||
class PDynArray;
|
||||
class PMap;
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
@ -53,10 +56,15 @@ public:
|
|||
|
||||
// Per-class information -------------------------------------
|
||||
PClass *ParentClass = nullptr; // the class this class derives from
|
||||
const size_t *Pointers = nullptr; // object pointers defined by this class *only*
|
||||
const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default
|
||||
const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers.
|
||||
const std::pair<size_t,PType *> *MapPointers = nullptr; // maps containing object pointers.
|
||||
const size_t * Pointers = nullptr; // native object pointers defined by this class *only*
|
||||
|
||||
mutable size_t FlatPointersSize = 0;
|
||||
mutable const std::pair<size_t, PObjectPointer*> * FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default.
|
||||
mutable size_t ArrayPointersSize = 0;
|
||||
mutable const std::pair<size_t, PDynArray *> * ArrayPointers = nullptr; // dynamic arrays containing object pointers.
|
||||
mutable size_t MapPointersSize = 0;
|
||||
mutable const std::pair<size_t, PMap *> * MapPointers = nullptr; // maps containing object pointers.
|
||||
|
||||
uint8_t *Defaults = nullptr;
|
||||
uint8_t *Meta = nullptr; // Per-class static script data
|
||||
unsigned Size = sizeof(DObject);
|
||||
|
|
@ -86,9 +94,11 @@ public:
|
|||
PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0);
|
||||
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void BuildArrayPointers();
|
||||
void BuildMapPointers();
|
||||
|
||||
void BuildFlatPointers() const;
|
||||
void BuildArrayPointers() const;
|
||||
void BuildMapPointers() const;
|
||||
|
||||
void DestroySpecials(void *addr);
|
||||
void DestroyMeta(void *addr);
|
||||
const PClass *NativeClass() const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue