From 7c8cff64e682cb6ce39b4b111937a094b9571945 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 3 Apr 2016 17:45:04 -0500 Subject: [PATCH] Added code to initialize and destroy string variables in classes - Will require being able to add strings to non-native classes to actually test this. --- src/dobject.cpp | 56 ++++++----- src/dobjtype.cpp | 144 +++++++++++++++++++++++++++ src/dobjtype.h | 27 +++++ src/tarray.h | 14 ++- src/thingdef/thingdef_expression.cpp | 2 +- 5 files changed, 212 insertions(+), 31 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index d7e23bdb05..511f3e5f01 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -257,46 +257,50 @@ DObject::DObject (PClass *inClass) DObject::~DObject () { - if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) + if (!PClass::bShutdown) { - DObject **probe; PClass *type = GetClass(); - - if (!(ObjectFlags & OF_YesReallyDelete)) + if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { - Printf ("Warning: '%s' is freed outside the GC process.\n", - type != NULL ? type->TypeName.GetChars() : "==some object=="); - } + DObject **probe; - // Find all pointers that reference this object and NULL them. - StaticPointerSubstitution(this, NULL); - - // Now unlink this object from the GC list. - for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) - { - if (*probe == this) + if (!(ObjectFlags & OF_YesReallyDelete)) { - *probe = ObjNext; - if (&ObjNext == GC::SweepPos) - { - GC::SweepPos = probe; - } - break; + Printf("Warning: '%s' is freed outside the GC process.\n", + type != NULL ? type->TypeName.GetChars() : "==some object=="); } - } - // If it's gray, also unlink it from the gray list. - if (this->IsGray()) - { - for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) + // Find all pointers that reference this object and NULL them. + StaticPointerSubstitution(this, NULL); + + // Now unlink this object from the GC list. + for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) { if (*probe == this) { - *probe = GCNext; + *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; + } + } + } } + type->DestroySpecials(this); } } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 11fd04e82c..fbc3ceb730 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -500,6 +500,36 @@ void PType::SkipValue(FArchive &ar, int tag) } } +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) const +{ +} + +//========================================================================== +// +// PType :: InitializeValue +// +//========================================================================== + +void PType::InitializeValue(void *addr, const void *def) const +{ +} + +//========================================================================== +// +// PType :: DestroyValue +// +//========================================================================== + +void PType::DestroyValue(void *addr) const +{ +} + //========================================================================== // // PType :: SetValue @@ -1497,6 +1527,43 @@ bool PString::ReadValue(FArchive &ar, void *addr) const return true; } +//========================================================================== +// +// PString :: SetDefaultValue +// +//========================================================================== + +void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + new((BYTE *)base + offset) FString; + if (special != NULL) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PString :: InitializeValue +// +//========================================================================== + +void PString::InitializeValue(void *addr, const void *def) const +{ + new(addr) FString(*(FString *)def); +} + +//========================================================================== +// +// PString :: DestroyValue +// +//========================================================================== + +void PString::DestroyValue(void *addr) const +{ + ((FString *)addr)->~FString(); +} + /* PName ******************************************************************/ IMPLEMENT_CLASS(PName) @@ -2328,6 +2395,20 @@ bool PArray::ReadValue(FArchive &ar, void *addr) const return false; } +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetDefaultValue(base, offset + i*ElementSize, special); + } +} + //========================================================================== // // NewArray @@ -2581,6 +2662,23 @@ PStruct::PStruct(FName name, DObject *outer) { } +//========================================================================== +// +// PStruct :: SetDefaultValue +// +//========================================================================== + +void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetDefaultValue(base, offset + field->Offset, special); + } + } +} + //========================================================================== // // PStruct :: WriteValue @@ -3287,9 +3385,50 @@ DObject *PClass::CreateNew() const ConstructNative (mem); ((DObject *)mem)->SetClass (const_cast(this)); + if (Defaults != NULL) + { + InitializeSpecials(mem); + } return (DObject *)mem; } +//========================================================================== +// +// PClass :: InitializeSpecials +// +// Initialize special fields of a newly-created instance (e.g. strings). +// +//========================================================================== + +void PClass::InitializeSpecials(void *addr) const +{ + if (ParentClass != NULL) + { + ParentClass->InitializeSpecials(addr); + } + for (auto tao : SpecialInits) + { + tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults + tao.second); + } +} + +//========================================================================== +// +// PClass :: DestroySpecials +// +//========================================================================== + +void PClass::DestroySpecials(void *addr) const +{ + if (ParentClass != NULL) + { + ParentClass->DestroySpecials(addr); + } + for (auto tao : SpecialInits) + { + tao.first->DestroyValue((BYTE *)addr + tao.second); + } +} //========================================================================== // // PClass :: Derive @@ -3388,6 +3527,11 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) { Defaults = (BYTE *)M_Realloc(Defaults, Size); memset(Defaults + oldsize, 0, Size - oldsize); + // If this is a native class, then we must not initialize and + // destroy any of its members. We do, however, initialize the + // default instance since it's not a normal instance of the class. + type->SetDefaultValue(Defaults, field->Offset, + bRuntimeClass ? &SpecialInits : NULL); } return field; } diff --git a/src/dobjtype.h b/src/dobjtype.h index 6798045663..fe04bc6343 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -7,6 +7,8 @@ #include "vm.h" +typedef std::pair FTypeAndOffset; + // Variable/parameter/field flags ------------------------------------------- // Making all these different storage types use a common set of flags seems @@ -200,6 +202,22 @@ public: static void SkipValue(FArchive &ar); static void SkipValue(FArchive &ar, int tag); + // Sets the default value for this type at (base + offset) + // If the default value is binary 0, then this function doesn't need + // to do anything, because PClass::Extend() takes care of that. + // + // The stroffs array is so that types that need special initialization + // and destruction (e.g. strings) can add their offsets to it for special + // initialization when the object is created and destruction when the + // object is destroyed. + virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; + + // Initialize the value, if needed (e.g. strings) + virtual void InitializeValue(void *addr, const void *def) const; + + // Destroy the value, if needed (e.g. strings) + virtual void DestroyValue(void *addr) const; + // Sets the value of a variable of this type at (addr) virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); @@ -404,6 +422,9 @@ public: void WriteValue(FArchive &ar, const void *addr) const override; bool ReadValue(FArchive &ar, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; }; // Variations of integer types ---------------------------------------------- @@ -577,6 +598,8 @@ public: void WriteValue(FArchive &ar, const void *addr) const override; bool ReadValue(FArchive &ar, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *special) const override; + protected: PArray(); }; @@ -637,6 +660,7 @@ public: void WriteValue(FArchive &ar, const void *addr) const override; bool ReadValue(FArchive &ar, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; static void WriteFields(FArchive &ar, const void *addr, const TArray &fields); bool ReadFields(FArchive &ar, void *addr) const; @@ -697,7 +721,9 @@ class PClass : public PStruct protected: // We unravel _WITH_META here just as we did for PType. enum { MetaClassNum = CLASSREG_PClassClass }; + TArray SpecialInits; virtual void Derive(PClass *newclass); + void InitializeSpecials(void *addr) const; public: typedef PClassClass MetaClass; MetaClass *GetClass() const; @@ -728,6 +754,7 @@ public: PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); + void DestroySpecials(void *addr) const; const PClass *NativeClass() const; // Returns true if this type is an ancestor of (or same as) the passed type. diff --git a/src/tarray.h b/src/tarray.h index 3ef4f2d990..bd28d86abc 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -94,17 +94,23 @@ public: { return &Array[0]; } + const_iterator begin() const + { + return &Array[0]; + } + const_iterator cbegin() const + { + return &Array[0]; + } iterator end() { return &Array[Count]; } - - const_iterator cbegin() const + const_iterator end() const { - return &Array[0]; + return &Array[Count]; } - const_iterator cend() const { return &Array[Count]; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 0312126d45..e1a9e653ef 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3039,7 +3039,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit indexv(index->Emit(build)); int shiftbits = 0; - while (1 << shiftbits < arraytype->ElementSize) + while (1u << shiftbits < arraytype->ElementSize) { shiftbits++; }