From 4ca69f10c72456f04d9e225cd6e394a948ba8a63 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 10:55:59 +0100 Subject: [PATCH 1/6] - removed a few unused definitions. --- src/oplsynth/muslib.h | 18 ------------------ src/r_data/renderstyle.cpp | 2 +- src/r_data/renderstyle.h | 4 ---- src/r_draw.cpp | 4 ++-- 4 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index e4b4ac5cbd..9091c85366 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -83,26 +83,9 @@ class FileReader; /* Global Definitions */ -#define MLVERSION 0x0175 -#define MLVERSIONSTR "1.75" -extern char MLversion[]; -extern char MLcopyright[]; - #define CHANNELS 16 // total channels 0..CHANNELS-1 #define PERCUSSION 15 // percussion channel -/* MUS file header structure */ -struct MUSheader { - char ID[4]; // identifier "MUS" 0x1A - WORD scoreLen; // score length - WORD scoreStart; // score start - WORD channels; // primary channels - WORD sec_channels; // secondary channels (??) - WORD instrCnt; // used instrument count - WORD dummy; -// WORD instruments[...]; // table of used instruments -}; - /* OPL2 instrument */ struct OPL2instrument { /*00*/ BYTE trem_vibr_1; /* OP 1: tremolo/vibrato/sustain/KSR/multi */ @@ -131,7 +114,6 @@ struct OP2instrEntry { }; #define FL_FIXED_PITCH 0x0001 // note has fixed pitch (see below) -#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) #define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one diff --git a/src/r_data/renderstyle.cpp b/src/r_data/renderstyle.cpp index 6e656f715a..5c9dcc429b 100644 --- a/src/r_data/renderstyle.cpp +++ b/src/r_data/renderstyle.cpp @@ -103,7 +103,7 @@ double GetAlpha(int type, double alpha) switch (type) { case STYLEALPHA_Zero: return 0; - case STYLEALPHA_One: return OPAQUE; + case STYLEALPHA_One: return 1.; case STYLEALPHA_Src: return alpha; case STYLEALPHA_InvSrc: return 1. - alpha; default: return 0; diff --git a/src/r_data/renderstyle.h b/src/r_data/renderstyle.h index 501c14c5f9..947f9afeda 100644 --- a/src/r_data/renderstyle.h +++ b/src/r_data/renderstyle.h @@ -44,10 +44,6 @@ enum { OPAQUE = 65536, - TRANSLUC25 = (OPAQUE / 4), - TRANSLUC33 = (OPAQUE / 3), - TRANSLUC66 = ((OPAQUE * 2) / 3), - TRANSLUC75 = ((OPAQUE * 3) / 4), }; // Legacy render styles diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 10bc104c2e..c4449f73bb 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -383,7 +383,7 @@ namespace swrenderer if (style.BlendOp == STYLEOP_Shadow) { style = LegacyRenderStyles[STYLE_TranslucentStencil]; - alpha = TRANSLUC33; + alpha = OPAQUE / 3; color = 0; } @@ -393,7 +393,7 @@ namespace swrenderer } else if (style.Flags & STYLEF_Alpha1) { - alpha = FRACUNIT; + alpha = OPAQUE; } else { From 56024a1ebe5aa6f3de31e5366f22b3f629c932de Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 14:48:27 +0100 Subject: [PATCH 2/6] - implemented the backend for dynamic arrays. Still needs thorough testing but it should be complete. - use a memory arena to store flat pointers so that the messed up cleanup can be avoided by deallocating this in bulk. - added a new SO opcode to the VM to execute a write barrier. This is necessary for all objects that are not linked into one global table, i.e. everything except thinkers and class types. - always use the cheaper LOS opcode for reading pointers to classes and defaults because these cannot be destroyed during normal operation. - removed the pointless validation from String.Mid. If the values are read as unsigned the internal validation of FString::Mid will automatically ensure proper results. --- src/dobject.cpp | 39 +++ src/dobjtype.cpp | 420 ++++++++++++++++------- src/dobjtype.h | 15 +- src/scripting/codegeneration/codegen.cpp | 13 +- src/scripting/thingdef_data.cpp | 21 +- src/scripting/vm/vm.h | 2 + src/scripting/vm/vmexec.h | 11 + src/scripting/vm/vmops.h | 2 + 8 files changed, 376 insertions(+), 147 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 10b37f636e..63c7bb688d 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -397,6 +397,23 @@ size_t DObject::PropagateMark() GC::Mark((DObject **)((BYTE *)this + *offsets)); offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + GC::Mark(&p); + } + offsets++; + } + return info->Size; } return 0; @@ -427,6 +444,28 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld) } offsets++; } + + offsets = info->ArrayPointers; + if (offsets == NULL) + { + const_cast(info)->BuildArrayPointers(); + offsets = info->ArrayPointers; + } + while (*offsets != ~(size_t)0) + { + auto aray = (TArray*)((BYTE *)this + *offsets); + for (auto &p : *aray) + { + if (p == old) + { + p = notOld; + changed++; + } + } + offsets++; + } + + return changed; } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 958cd4275a..034510ff94 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -65,6 +65,7 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- +FMemArena FlatpointerArena; // stores the flat pointers because freeing them individually is rather messy. FNamespaceManager Namespaces; FTypeTable TypeTable; @@ -99,7 +100,7 @@ PPointer *TypeVoidPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -// A harmless non-NULL FlatPointer for classes without pointers. +// A harmless non-nullptr FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- @@ -118,7 +119,7 @@ void DumpTypeTable() { int len = 0; Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { Printf(" -> %s", ty->DescriptiveName()); len++; @@ -161,7 +162,7 @@ IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== PClassType::PClassType() -: TypeTableType(NULL) +: TypeTableType(nullptr) { } @@ -211,7 +212,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(NULL) +: Size(size), Align(align), HashNext(nullptr) { mDescriptiveName = "Type"; loadOp = OP_NOP; @@ -286,6 +287,10 @@ void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) con { } +void PType::SetPointerArray(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -831,7 +836,7 @@ PBool::PBool() MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); - assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); maxsym->Value = 1; } @@ -1147,7 +1152,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const { if (base != nullptr) new((BYTE *)base + offset) FString; - if (special != NULL) + if (special != nullptr) { special->Push(std::make_pair(this, offset)); } @@ -1415,7 +1420,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(NULL), IsConst(false) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) { mDescriptiveName = "NullPointer"; SetOps(); @@ -1442,8 +1447,9 @@ PPointer::PPointer(PType *pointsat, bool isconst) void PPointer::SetOps() { - storeOp = OP_SP; loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + storeOp = (loadOp == OP_LO && !static_cast(PointedType)->IsDescendantOf(RUNTIME_CLASS(DThinker))) ? OP_SO : OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; } @@ -1476,7 +1482,7 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const //========================================================================== // -// PPointer :: SetDefaultValue +// PPointer :: SetPointer // //========================================================================== @@ -1547,7 +1553,7 @@ PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PPointer(type, isconst); TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); @@ -1606,18 +1612,6 @@ IMPLEMENT_POINTERS_START(PClassPointer) IMPLEMENT_POINTER(ClassRestriction) IMPLEMENT_POINTERS_END -//========================================================================== -// -// PClassPointer - Default Constructor -// -//========================================================================== - -PClassPointer::PClassPointer() -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) -{ - mDescriptiveName = "ClassPointer"; -} - //========================================================================== // // PClassPointer - Parameterized Constructor @@ -1629,6 +1623,10 @@ PClassPointer::PClassPointer(PClass *restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; + // class pointers do not need write barriers because all classes are stored in the global type table and won't get collected. + // This means we can use the cheapoer non-barriered opcodes here. + loadOp = OP_LOS; + storeOp = OP_SP; } //========================================================================== @@ -1683,7 +1681,7 @@ PClassPointer *NewClassPointer(PClass *restrict) { size_t bucket; PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); - if (ptype == NULL) + if (ptype == nullptr) { ptype = new PClassPointer(restrict); TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); @@ -1739,7 +1737,7 @@ PEnum *NewEnum(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); - if (etype == NULL) + if (etype == nullptr) { etype = new PEnum(name, outer); TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); @@ -1762,7 +1760,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PArray::PArray() -: ElementType(NULL), ElementCount(0) +: ElementType(nullptr), ElementCount(0) { mDescriptiveName = "Array"; } @@ -1902,7 +1900,7 @@ PArray *NewArray(PType *type, unsigned int count) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PArray(type, count); TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); @@ -1976,7 +1974,7 @@ PResizableArray *NewResizableArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { atype = new PResizableArray(type); TypeTable.AddType(atype, RUNTIME_CLASS(PResizableArray), (intptr_t)type, 0, bucket); @@ -1999,7 +1997,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PDynArray::PDynArray() -: ElementType(NULL) +: ElementType(nullptr) { mDescriptiveName = "DynArray"; Size = sizeof(FArray); @@ -2046,6 +2044,152 @@ void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PDynArray :: InitializeValue +// +//========================================================================== + +void PDynArray::InitializeValue(void *addr, const void *deff) const +{ + const FArray *def = (const FArray*)deff; + FArray *aray = (FArray*)addr; + + if (def == nullptr || def->Count == 0) + { + // Empty arrays do not need construction. + *aray = { nullptr, 0, 0 }; + } + else if (ElementType->GetRegType() != REGT_STRING) + { + // These are just integral values which can be done without any constructor hackery. + size_t blocksize = ElementType->Size * def->Count; + aray->Array = M_Malloc(blocksize); + memcpy(aray->Array, def->Array, blocksize); + aray->Most = aray->Count = def->Count; + } + else + { + // non-empty string arrays require explicit construction. + new(addr) TArray(*(TArray*)def); + } +} + +//========================================================================== +// +// PDynArray :: DestroyValue +// +//========================================================================== + +void PDynArray::DestroyValue(void *addr) const +{ + FArray *aray = (FArray*)addr; + + if (aray->Array != nullptr) + { + if (ElementType->GetRegType() != REGT_STRING) + { + M_Free(aray->Array); + } + else + { + // Damn those cursed strings again. :( + ((TArray*)addr)->~TArray(); + } + } + aray->Count = aray->Most = 0; + aray->Array = nullptr; +} + +//========================================================================== +// +// PDynArray :: SetDefaultValue +// +//========================================================================== + +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +{ + memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PDynArray :: SetPointer +// +//========================================================================== + +void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *special) const +{ + if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointer arrays for this class. + special->Push(offset); + } +} + +//========================================================================== +// +// PDynArray :: WriteValue +// +//========================================================================== + +void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FArray *aray = (FArray*)addr; + if (aray->Count > 0) + { + if (ar.BeginArray(key)) + { + const BYTE *addrb = (const BYTE *)aray->Array; + for (unsigned i = 0; i < aray->Count; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + } + } +} + +//========================================================================== +// +// PDynArray :: ReadValue +// +//========================================================================== + +bool PDynArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FArray *aray = (FArray*)addr; + DestroyValue(addr); // note that even after calling this we still got a validly constructed empty array. + + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + + size_t blocksize = ElementType->Size * count; + aray->Array = M_Malloc(blocksize); + memset(aray->Array, 0, blocksize); + aray->Most = aray->Count = count; + + BYTE *addrb = (BYTE *)aray->Array; + for (unsigned i = 0; iGetRegType() == REGT_STRING) new(addrb) FString; + readsomething |= ElementType->ReadValue(ar, nullptr, addrb); + addrb += ElementType->Size; + } + ar.EndArray(); + return readsomething; + } + return false; +} + //========================================================================== // // NewDynArray @@ -2059,7 +2203,7 @@ PDynArray *NewDynArray(PType *type) { size_t bucket; PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); - if (atype == NULL) + if (atype == nullptr) { FString backingname; @@ -2109,7 +2253,7 @@ IMPLEMENT_POINTERS_END //========================================================================== PMap::PMap() -: KeyType(NULL), ValueType(NULL) +: KeyType(nullptr), ValueType(nullptr) { mDescriptiveName = "Map"; Size = sizeof(FMap); @@ -2169,7 +2313,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) { size_t bucket; PType *maptype = TypeTable.FindType(RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, &bucket); - if (maptype == NULL) + if (maptype == nullptr) { maptype = new PMap(keytype, valuetype); TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); @@ -2308,7 +2452,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const foundsomething = true; const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == NULL) + if (sym == nullptr) { DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", label, TypeName.GetChars()); @@ -2332,7 +2476,7 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const // PStruct :: AddField // // Appends a new field to the end of a struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2350,10 +2494,10 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // its fields. Align = MAX(Align, type->Align); - if (Symbols.AddSymbol(field) == NULL) + if (Symbols.AddSymbol(field) == nullptr) { // name is already in use delete field; - return NULL; + return nullptr; } Fields.Push(field); @@ -2365,7 +2509,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) // PStruct :: AddField // // Appends a new native field to the struct. Returns either the new field -// or NULL if a symbol by that name already exists. +// or nullptr if a symbol by that name already exists. // //========================================================================== @@ -2408,7 +2552,7 @@ PStruct *NewStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2447,7 +2591,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) size_t bucket; if (outer == nullptr) outer = Namespaces.GlobalNamespace; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); - if (stype == NULL) + if (stype == nullptr) { stype = new PNativeStruct(name, outer); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); @@ -2466,7 +2610,7 @@ IMPLEMENT_CLASS(PField, false, false) //========================================================================== PField::PField() -: PSymbol(NAME_None), Offset(0), Type(NULL), Flags(0) +: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) { } @@ -2599,7 +2743,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray { size_t bucket; PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == NULL) + if (proto == nullptr) { proto = new PPrototype(rettypes, argtypes); TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); @@ -2689,7 +2833,7 @@ IMPLEMENT_POINTERS_END static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr) { - if (type != NULL) + if (type != nullptr) { RecurseWriteFields(type->ParentClass, ar, addr); // Don't write this part if it has no non-transient variables @@ -2773,7 +2917,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { // Only read it if the type is related to this one. const PClass *parent; - for (parent = this; parent != NULL; parent = parent->ParentClass) + for (parent = this; parent != nullptr; parent = parent->ParentClass) { if (parent == type) { @@ -2835,7 +2979,7 @@ void PClass::StaticInit () FAutoSegIterator probe(CRegHead, CRegTail); - while (*++probe != NULL) + while (*++probe != nullptr) { ((ClassReg *)*probe)->RegisterClass (); } @@ -2859,16 +3003,12 @@ void PClass::StaticInit () // // PClass :: StaticShutdown STATIC // -// Frees FlatPointers belonging to all classes. Only really needed to avoid -// memory leak warnings at exit. +// Frees all static class data. // //========================================================================== void PClass::StaticShutdown () { - TArray uniqueFPs(64); - unsigned int i, j; - // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { @@ -2876,7 +3016,8 @@ void PClass::StaticShutdown () } FunctionPtrList.Clear(); - // Make a full garbage collection here so that all destroyed but uncollected higher level objects that still exist can be properly taken down. + // Make a full garbage collection here so that all destroyed but uncollected higher level objects + // that still exist are properly taken down before the low level data is deleted. GC::FullGC(); // From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now. @@ -2886,33 +3027,7 @@ void PClass::StaticShutdown () // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. TypeTable.Clear(); Namespaces.ReleaseSymbols(); - - for (i = 0; i < PClass::AllClasses.Size(); ++i) - { - PClass *type = PClass::AllClasses[i]; - PClass::AllClasses[i] = NULL; - if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers) - { - // FlatPointers are shared by many classes, so we must check for - // duplicates and only delete those that are unique. - for (j = 0; j < uniqueFPs.Size(); ++j) - { - if (type->FlatPointers == uniqueFPs[j]) - { - break; - } - } - if (j == uniqueFPs.Size()) - { - uniqueFPs.Push(const_cast(type->FlatPointers)); - } - } - type->Destroy(); - } - for (i = 0; i < uniqueFPs.Size(); ++i) - { - delete[] uniqueFPs[i]; - } + FlatpointerArena.FreeAllBlocks(); bShutdown = true; AllClasses.Clear(); @@ -2946,7 +3061,7 @@ void PClass::StaticBootstrap() PClassClass *cls = new PClassClass; PClass::RegistrationInfo.SetupClass(cls); - // The PClassClass constructor initialized these to NULL, because the + // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. clscls->TypeTableType = cls; @@ -2971,6 +3086,7 @@ PClass::PClass() ParentClass = nullptr; Pointers = nullptr; FlatPointers = nullptr; + ArrayPointers = nullptr; HashNext = nullptr; Defaults = nullptr; bRuntimeClass = false; @@ -2990,10 +3106,10 @@ PClass::PClass() PClass::~PClass() { - if (Defaults != NULL) + if (Defaults != nullptr) { M_Free(Defaults); - Defaults = NULL; + Defaults = nullptr; } } @@ -3020,7 +3136,7 @@ PClass *ClassReg::RegisterClass() }; // Skip classes that have already been registered - if (MyClass != NULL) + if (MyClass != nullptr) { return MyClass; } @@ -3059,7 +3175,7 @@ PClass *ClassReg::RegisterClass() void ClassReg::SetupClass(PClass *cls) { - assert(MyClass == NULL); + assert(MyClass == nullptr); MyClass = cls; cls->TypeName = FName(Name+1); cls->Size = SizeOf; @@ -3082,7 +3198,7 @@ void PClass::InsertIntoHash () PType *found; found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != NULL) + if (found != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } @@ -3102,14 +3218,14 @@ void PClass::InsertIntoHash () const PClass *PClass::FindParentClass(FName name) const { - for (const PClass *type = this; type != NULL; type = type->ParentClass) + for (const PClass *type = this; type != nullptr; type = type->ParentClass) { if (type->TypeName == name) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3124,9 +3240,9 @@ PClass *PClass::FindClass (FName zaname) { if (zaname == NAME_None) { - return NULL; + return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, NULL)); + return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); } //========================================================================== @@ -3140,10 +3256,10 @@ PClass *PClass::FindClass (FName zaname) DObject *PClass::CreateNew() const { BYTE *mem = (BYTE *)M_Malloc (Size); - assert (mem != NULL); + assert (mem != nullptr); // Set this object's defaults before constructing it. - if (Defaults != NULL) + if (Defaults != nullptr) memcpy (mem, Defaults, Size); else memset (mem, 0, Size); @@ -3170,7 +3286,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(addr, defaults); for (auto tao : SpecialInits) { @@ -3195,7 +3311,7 @@ void PClass::DestroySpecials(void *addr) const { return; } - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->DestroySpecials(addr); for (auto tao : SpecialInits) { @@ -3231,7 +3347,7 @@ void PClass::InitializeDefaults() { if (IsKindOf(RUNTIME_CLASS(PClassActor))) { - assert(Defaults == NULL); + assert(Defaults == nullptr); Defaults = (BYTE *)M_Malloc(Size); // run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them. @@ -3248,7 +3364,7 @@ void PClass::InitializeDefaults() // Copy the defaults from the parent but leave the DObject part alone because it contains important data. - if (ParentClass->Defaults != NULL) + if (ParentClass->Defaults != nullptr) { memcpy(Defaults + sizeof(DObject), ParentClass->Defaults + sizeof(DObject), ParentClass->Size - sizeof(DObject)); if (Size > ParentClass->Size) @@ -3265,7 +3381,7 @@ void PClass::InitializeDefaults() if (bRuntimeClass) { // Copy parent values from the parent defaults. - assert(ParentClass != NULL); + assert(ParentClass != nullptr); ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) @@ -3404,14 +3520,14 @@ PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { - return NULL; + return nullptr; } size_t bucket; PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket); - if (found != NULL) + if (found != nullptr) { return static_cast(found); } @@ -3484,14 +3600,14 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) void PClass::BuildFlatPointers () { - if (FlatPointers != NULL) + if (FlatPointers != nullptr) { // Already built: Do nothing. return; } - else if (ParentClass == NULL) + else if (ParentClass == nullptr) { // No parent (i.e. DObject: FlatPointers is the same as Pointers. - if (Pointers == NULL) - { // No pointers: Make FlatPointers a harmless non-NULL. + if (Pointers == nullptr) + { // No pointers: Make FlatPointers a harmless non-nullptr. FlatPointers = &TheEnd; } else @@ -3536,7 +3652,7 @@ void PClass::BuildFlatPointers () { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1)); if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); @@ -3555,6 +3671,68 @@ void PClass::BuildFlatPointers () } } +//========================================================================== +// +// PClass :: BuildArrayPointers +// +// same as above, but creates a list to dynamic object arrays +// +//========================================================================== + +void PClass::BuildArrayPointers() +{ + 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; + } + else + { + ParentClass->BuildArrayPointers(); + + TArray ScriptPointers; + + // Collect all arrays to pointers in scripted fields. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointerArray(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (ScriptPointers.Size() == 0) + { // No new pointers: Just use the same ArrayPointers as the parent. + ArrayPointers = ParentClass->ArrayPointers; + } + 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++) + { + } + + // Concatenate them into a new array + size_t *flat = (size_t*)FlatpointerArena.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1)); + if (numSuperPointers > 0) + { + memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0; + ArrayPointers = flat; + } + } +} + //========================================================================== // // PClass :: NativeClass @@ -3604,18 +3782,18 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) { size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - if (bucketnum != NULL) + if (bucketnum != nullptr) { *bucketnum = bucket; } - for (PType *type = TypeHash[bucket]; type != NULL; type = type->HashNext) + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } } - return NULL; + return nullptr; } //========================================================================== @@ -3630,13 +3808,13 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si void FTypeTable::ReplaceType(PType *newtype, PType *oldtype, size_t bucket) { - for (PType **type_p = &TypeHash[bucket]; *type_p != NULL; type_p = &(*type_p)->HashNext) + for (PType **type_p = &TypeHash[bucket]; *type_p != nullptr; type_p = &(*type_p)->HashNext) { PType *type = *type_p; if (type == oldtype) { newtype->HashNext = type->HashNext; - type->HashNext = NULL; + type->HashNext = nullptr; *type_p = newtype; break; } @@ -3654,7 +3832,7 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t #ifdef _DEBUG size_t bucketcheck; assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); - assert(FindType(metatype, parm1, parm2, &bucketcheck) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif type->HashNext = TypeHash[bucket]; @@ -3677,7 +3855,7 @@ void FTypeTable::AddType(PType *type) metatype = type->GetClass()->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - assert(FindType(metatype, parm1, parm2, NULL) == NULL && "Type must not be inserted more than once"); + assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; @@ -3732,7 +3910,7 @@ void FTypeTable::Mark() { for (int i = HASH_SIZE - 1; i >= 0; --i) { - if (TypeHash[i] != NULL) + if (TypeHash[i] != nullptr) { GC::Mark(TypeHash[i]); } @@ -3790,7 +3968,7 @@ PSymbol::~PSymbol() } PSymbolTable::PSymbolTable() -: ParentSymbolTable(NULL) +: ParentSymbolTable(nullptr) { } @@ -3833,24 +4011,24 @@ void PSymbolTable::SetParentTable (PSymbolTable *parent) PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL && searchparents && ParentSymbolTable != NULL) + if (value == nullptr && searchparents && ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbol(symname, searchparents); } - return value != NULL ? *value : NULL; + return value != nullptr ? *value : nullptr; } PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) { PSymbol * const *value = Symbols.CheckKey(symname); - if (value == NULL) + if (value == nullptr) { - if (ParentSymbolTable != NULL) + if (ParentSymbolTable != nullptr) { return ParentSymbolTable->FindSymbolInTable(symname, symtable); } - symtable = NULL; - return NULL; + symtable = nullptr; + return nullptr; } symtable = this; return *value; @@ -3859,9 +4037,9 @@ PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { // Symbols that already exist are not inserted. - if (Symbols.CheckKey(sym->SymbolName) != NULL) + if (Symbols.CheckKey(sym->SymbolName) != nullptr) { - return NULL; + return nullptr; } Symbols.Insert(sym->SymbolName, sym); return sym; @@ -3878,16 +4056,16 @@ PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) { // If a symbol with a matching name exists, take its place and return it. PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); - if (symslot != NULL) + if (symslot != nullptr) { PSymbol *oldsym = *symslot; *symslot = newsym; return oldsym; } - // Else, just insert normally and return NULL since there was no + // Else, just insert normally and return nullptr since there was no // symbol to replace. Symbols.Insert(newsym->SymbolName, newsym); - return NULL; + return nullptr; } IMPLEMENT_CLASS(PNamespace, false, true) @@ -3969,7 +4147,7 @@ void RemoveUnusedSymbols() // We do not need any non-field and non-function symbols in structs and classes anymore. for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) { - for (PType *ty = TypeTable.TypeHash[i]; ty != NULL; ty = ty->HashNext) + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 60d4109185..3e204da62b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -247,6 +247,7 @@ public: // object is destroyed. virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) const; virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; + virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) virtual void InitializeValue(void *addr, const void *def) const; @@ -534,7 +535,7 @@ class PClassPointer : public PPointer DECLARE_CLASS(PClassPointer, PPointer); HAS_OBJECT_POINTERS; public: - PClassPointer(class PClass *restrict); + PClassPointer(class PClass *restrict = nullptr); class PClass *ClassRestriction; @@ -542,8 +543,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PClassPointer(); }; // Struct/class fields ------------------------------------------------------ @@ -657,6 +656,14 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) const override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; + void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const override; + protected: PDynArray(); }; @@ -801,6 +808,7 @@ public: PClass *ParentClass; // the class this class derives from const size_t *Pointers; // object pointers defined by this class *only* const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default + const size_t *ArrayPointers; // dynamic arrays containing object pointers. BYTE *Defaults; bool bRuntimeClass; // class was defined at run-time, not compile-time bool bExported; // This type has been declared in a script @@ -818,6 +826,7 @@ public: PField *AddField(FName name, PType *type, DWORD flags=0) override; void InitializeActorInfo(); void BuildFlatPointers(); + void BuildArrayPointers(); void DestroySpecials(void *addr) const; const PClass *NativeClass() const; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 4d6376f3bc..a3dc066e98 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -542,7 +542,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) { tag = ATAG_STATE; } - else if (value.Type->GetLoadOp() == OP_LO) + else if (value.Type->GetLoadOp() != OP_LP) { tag = ATAG_OBJECT; } @@ -6356,7 +6356,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ob.Free(build); ExpEmit meta(build, REGT_POINTER); build->Emit(OP_META, meta.RegNum, ob.RegNum); - build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; } @@ -8874,7 +8874,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) op.Free(build); } ExpEmit to(build, REGT_POINTER); - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); return to; } @@ -8946,7 +8946,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) build->Emit(OP_LKP, to.RegNum, op.RegNum); op = to; } - build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return to; } @@ -10683,8 +10683,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) case REGT_POINTER: { - bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); - build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ValueType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC)); break; } case REGT_STRING: @@ -10824,7 +10823,7 @@ ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) { TArray cvalues; for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); - StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() != OP_LP ? ATAG_OBJECT : ATAG_GENERIC); break; } } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8786a31bf1..97f6ae10b3 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1141,19 +1141,8 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) DEFINE_ACTION_FUNCTION(FStringStruct, Mid) { PARAM_SELF_STRUCT_PROLOGUE(FString); - PARAM_INT(ipos); - PARAM_INT(ilen); - // validate. we don't want to crash if someone passes negative values. - // with size_t it's handled naturally I think, as it's unsigned, but not in ZScript. - if (ipos < 0) ipos = 0; - if (ilen < 0) ilen = 0; - // convert to size_t to prevent overflows here - size_t slen = self->Len(); - size_t pos = (size_t)ipos; - size_t len = (size_t)ilen; - if (pos > slen) pos = slen - 1; - if (pos + len > slen) - len = slen - pos; + PARAM_UINT(pos); + PARAM_UINT(len); FString s = self->Mid(pos, len); ACTION_RETURN_STRING(s); } @@ -1161,7 +1150,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) DEFINE_ACTION_FUNCTION(FStringStruct, Len) { PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT(self->Len()); + ACTION_RETURN_INT((int)self->Len()); } // CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. @@ -1169,7 +1158,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_STRING(""); ACTION_RETURN_STRING(FString((*self)[pos])); @@ -1179,7 +1168,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) { PARAM_SELF_STRUCT_PROLOGUE(FString); PARAM_INT(pos); - int slen = self->Len(); + int slen = (int)self->Len(); if (pos < 0 || pos >= slen) ACTION_RETURN_INT(0); ACTION_RETURN_INT((*self)[pos]); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 1a5c10b4e5..8b8e3c8643 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -997,6 +997,7 @@ void NullParam(const char *varname); // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; +#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; #define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; #define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; @@ -1040,6 +1041,7 @@ void NullParam(const char *varname); #define PARAM_PROLOGUE int paramnum = -1; #define PARAM_INT(x) ++paramnum; PARAM_INT_AT(paramnum,x) +#define PARAM_UINT(x) ++paramnum; PARAM_UINT_AT(paramnum,x) #define PARAM_BOOL(x) ++paramnum; PARAM_BOOL_AT(paramnum,x) #define PARAM_NAME(x) ++paramnum; PARAM_NAME_AT(paramnum,x) #define PARAM_SOUND(x) ++paramnum; PARAM_SOUND_AT(paramnum,x) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 38dbbc411c..b9f8e81ca3 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -347,6 +347,17 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(void **)ptr = reg.a[B]; NEXTOP; + OP(SO): + ASSERTA(a); ASSERTA(B); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + *(void **)ptr = reg.a[B]; + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; + OP(SO_R): + ASSERTA(a); ASSERTA(B); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + GC::WriteBarrier((DObject*)*(void **)ptr); + NEXTOP; OP(SV2): ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3fc3d7643f..7128f1e43c 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -70,6 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string xx(SS_R, ss, RPRSRI, NOP, 0, 0), xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types +xx(SO_R, sp, RPRPRI, NOP, 0, 0), xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 From 776509e68aa696d4fba125c646c760f1ad8dc50d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 18:12:38 +0100 Subject: [PATCH 3/6] - let skip_super use the AActor assignment operator. The blanket memcpy it used was clobbering some data. - moved the Finalize method from PClassActor to AActor. Now that defaults get their vtbl pointer initialized this will actually work. --- src/actor.h | 1 + src/g_inventory/a_pickups.cpp | 4 ++-- src/g_inventory/a_pickups.h | 1 + src/g_inventory/a_weapons.cpp | 3 ++- src/g_inventory/a_weapons.h | 4 ++-- src/info.cpp | 8 ++++---- src/info.h | 1 - src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 15 +-------------- 10 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/actor.h b/src/actor.h index 05b1aa076b..4016d447b4 100644 --- a/src/actor.h +++ b/src/actor.h @@ -596,6 +596,7 @@ public: AActor &operator= (const AActor &other); ~AActor (); + virtual void Finalize(FStateDefinitions &statedef); virtual void OnDestroy() override; virtual void Serialize(FSerializer &arc) override; virtual void PostSerialize() override; diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index fc35d2da4a..66f51e92ef 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -73,10 +73,10 @@ size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass return changed; } -void PClassInventory::Finalize(FStateDefinitions &statedef) +void AInventory::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); - ((AActor*)Defaults)->flags |= MF_SPECIAL; + flags |= MF_SPECIAL; } IMPLEMENT_CLASS(AInventory, false, true) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 7ca317397a..be6280c0a7 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -72,6 +72,7 @@ class AInventory : public AActor HAS_OBJECT_POINTERS public: + virtual void Finalize(FStateDefinitions &statedef) override; virtual void Serialize(FSerializer &arc) override; virtual void MarkPrecacheSounds() const override; virtual void OnDestroy() override; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 24661dfd19..7c2a0fb815 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -155,13 +155,14 @@ void PClassWeapon::DeriveData(PClass *newclass) // //=========================================================================== -void PClassWeapon::Finalize(FStateDefinitions &statedef) +void AWeapon::Finalize(FStateDefinitions &statedef) { Super::Finalize(statedef); FState *ready = FindState(NAME_Ready); FState *select = FindState(NAME_Select); FState *deselect = FindState(NAME_Deselect); FState *fire = FindState(NAME_Fire); + auto TypeName = GetClass()->TypeName; // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 21eaf9b890..b2eeaf9514 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -94,7 +94,6 @@ protected: virtual void DeriveData(PClass *newclass); public: PClassWeapon(); - void Finalize(FStateDefinitions &statedef); int SlotNumber; int SlotPriority; @@ -135,7 +134,8 @@ public: virtual void MarkPrecacheSounds() const; - virtual void Serialize(FSerializer &arc) override; + void Finalize(FStateDefinitions &statedef) override; + void Serialize(FSerializer &arc) override; void PostMorphWeapon(); diff --git a/src/info.cpp b/src/info.cpp index a424c890f7..c86486b5e0 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -429,20 +429,20 @@ void PClassActor::SetDropItems(DDropItem *drops) // //========================================================================== -void PClassActor::Finalize(FStateDefinitions &statedef) +void AActor::Finalize(FStateDefinitions &statedef) { - AActor *defaults = (AActor*)Defaults; + AActor *defaults = this; try { - statedef.FinishStates(this, defaults); + statedef.FinishStates(GetClass(), defaults); } catch (CRecoverableError &) { statedef.MakeStateDefines(NULL); throw; } - statedef.InstallStates(this, defaults); + statedef.InstallStates(GetClass(), defaults); statedef.MakeStateDefines(NULL); } diff --git a/src/info.h b/src/info.h index 4a6baa671f..3a20994f54 100644 --- a/src/info.h +++ b/src/info.h @@ -259,7 +259,6 @@ public: size_t PropagateMark(); bool SetReplacement(FName replaceName); void SetDropItems(DDropItem *drops); - virtual void Finalize(FStateDefinitions &statedef); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 505585937e..fc411186a6 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1155,7 +1155,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns) } try { - info->Finalize(bag.statedef); + GetDefaultByType(info)->Finalize(bag.statedef); } catch (CRecoverableError &err) { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 6823001475..4822a27b3e 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -560,7 +560,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) return; } - memcpy ((void *)defaults, (void *)GetDefault(), sizeof(AActor)); + *defaults = *GetDefault(); ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 44428ab882..93f41746f2 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2447,19 +2447,6 @@ void ZCCCompiler::CompileStates() continue; } - // Same here, hack in the DVMObject as they weren't in the list originally - // TODO: process them in a non hackish way obviously - if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false) - { - auto vmtype = static_cast(c->Type()->ParentClass); - if (vmtype->StateList == nullptr) - { - FStateDefinitions vmstates; - vmstates.MakeStateDefines(dyn_cast(vmtype->ParentClass)); - vmtype->Finalize(vmstates); - } - } - FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; statedef.MakeStateDefines(dyn_cast(c->Type()->ParentClass)); @@ -2658,7 +2645,7 @@ void ZCCCompiler::CompileStates() } try { - static_cast(c->Type())->Finalize(statedef); + GetDefaultByType(c->Type())->Finalize(statedef); } catch (CRecoverableError &err) { From 7ed554158c98cebe56c1d3a29a1138147546962f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 19:02:27 +0100 Subject: [PATCH 4/6] - got rid of PClassWeapon. Still 5 subclasses of PClass left... --- src/d_net.cpp | 6 +- src/dobject.h | 1 - src/dobjtype.cpp | 8 +- src/fragglescript/t_func.cpp | 10 +- src/g_inventory/a_weapons.cpp | 199 +++++++++----------- src/g_inventory/a_weapons.h | 41 ++-- src/scripting/thingdef_properties.cpp | 6 +- wadsrc/static/zscript/inventory/weapons.txt | 2 + 8 files changed, 118 insertions(+), 155 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 93f6a621b7..c38a7cefeb 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2638,7 +2638,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) } for(i = 0; i < count; ++i) { - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[pnum].weapons.AddSlot(slot, wpn, pnum == consoleplayer); } } @@ -2647,7 +2647,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlot(slot, wpn, player == consoleplayer); } break; @@ -2655,7 +2655,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) case DEM_ADDSLOTDEFAULT: { int slot = ReadByte(stream); - PClassWeapon *wpn = Net_ReadWeapon(stream); + PClassActor *wpn = Net_ReadWeapon(stream); players[player].weapons.AddSlotDefault(slot, wpn, player == consoleplayer); } break; diff --git a/src/dobject.h b/src/dobject.h index 6b9b87c759..1a7afaea00 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -94,7 +94,6 @@ enum CLASSREG_PClass, CLASSREG_PClassActor, CLASSREG_PClassInventory, - CLASSREG_PClassWeapon, CLASSREG_PClassPlayerPawn, CLASSREG_PClassType, CLASSREG_PClassClass, diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 034510ff94..d5653fc6d8 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3030,6 +3030,13 @@ void PClass::StaticShutdown () FlatpointerArena.FreeAllBlocks(); bShutdown = true; + for (unsigned i = 0; i < PClass::AllClasses.Size(); ++i) + { + PClass *type = PClass::AllClasses[i]; + PClass::AllClasses[i] = NULL; + type->Destroy(); + } + AllClasses.Clear(); PClassActor::AllActorClasses.Clear(); @@ -3129,7 +3136,6 @@ PClass *ClassReg::RegisterClass() &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, - &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 20b53c8fd1..0ee391e215 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2675,8 +2675,8 @@ void FParser::SF_PlayerWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; @@ -2686,7 +2686,7 @@ void FParser::SF_PlayerWeapon() { AActor * wp = players[playernum].mo->FindInventory(ti); t_return.type = svt_int; - t_return.value.i = wp!=NULL;; + t_return.value.i = wp!=NULL; return; } else @@ -2756,8 +2756,8 @@ void FParser::SF_PlayerSelectedWeapon() script_error("weaponnum out of range! %d\n", weaponnum); return; } - PClassWeapon * ti = static_cast(PClass::FindActor(WeaponNames[weaponnum])); - if (!ti) + auto ti = PClass::FindActor(WeaponNames[weaponnum]); + if (!ti || !ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { script_error("incompatibility in playerweapon %d\n", weaponnum); return; diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 7c2a0fb815..a916531be6 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -113,42 +113,11 @@ FString WeaponSection; TArray KeyConfWeapons; FWeaponSlots *PlayingKeyConf; -TArray Weapons_ntoh; -TMap Weapons_hton; +TArray Weapons_ntoh; +TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon, false, false) - -//=========================================================================== -// -// -// -//=========================================================================== - -PClassWeapon::PClassWeapon() -{ - SlotNumber = -1; - SlotPriority = INT_MAX; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassWeapon::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - Super::DeriveData(newclass); - PClassWeapon *newc = static_cast(newclass); - - newc->SlotNumber = SlotNumber; - newc->SlotPriority = SlotPriority; -} - - //=========================================================================== // // @@ -273,7 +242,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am bool gotSome = CheckAmmo (PrimaryFire, false) || CheckAmmo (AltFire, false); if (!gotSome && autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return gotSome; } @@ -282,10 +251,10 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { return true; } - count1 = (Ammo1 != NULL) ? Ammo1->Amount : 0; - count2 = (Ammo2 != NULL) ? Ammo2->Amount : 0; + count1 = (Ammo1 != nullptr) ? Ammo1->Amount : 0; + count2 = (Ammo2 != nullptr) ? Ammo2->Amount : 0; - if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == NULL)) + if ((WeaponFlags & WIF_DEHAMMO) && (Ammo1 == nullptr)) { lAmmoUse1 = 0; } @@ -307,7 +276,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am { enoughmask = 1 << altFire; } - if (altFire && FindState(NAME_AltFire) == NULL) + if (altFire && FindState(NAME_AltFire) == nullptr) { // If this weapon has no alternate fire, then there is never enough ammo for it enough &= 1; } @@ -318,7 +287,7 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am // out of ammo, pick a weapon to change to if (autoSwitch) { - barrier_cast(Owner)->PickNewWeapon (NULL); + barrier_cast(Owner)->PickNewWeapon (nullptr); } return false; } @@ -353,7 +322,7 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) } if (!altFire) { - if (Ammo1 != NULL) + if (Ammo1 != nullptr) { if (ammouse >= 0 && (WeaponFlags & WIF_DEHAMMO)) { @@ -364,25 +333,25 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) Ammo1->Amount -= AmmoUse1; } } - if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != NULL) + if ((WeaponFlags & WIF_PRIMARY_USES_BOTH) && Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } } else { - if (Ammo2 != NULL) + if (Ammo2 != nullptr) { Ammo2->Amount -= AmmoUse2; } - if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != NULL) + if ((WeaponFlags & WIF_ALT_USES_BOTH) && Ammo1 != nullptr) { Ammo1->Amount -= AmmoUse1; } } - if (Ammo1 != NULL && Ammo1->Amount < 0) + if (Ammo1 != nullptr && Ammo1->Amount < 0) Ammo1->Amount = 0; - if (Ammo2 != NULL && Ammo2->Amount < 0) + if (Ammo2 != nullptr && Ammo2->Amount < 0) Ammo2->Amount = 0; } return true; @@ -547,14 +516,14 @@ FState *AWeapon::GetStateForButtonName (FName button) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon(static_cast(PClass::FindClass(type))); + return AddWeapon(static_cast(PClass::FindClass(type))); } -bool FWeaponSlot::AddWeapon(PClassWeapon *type) +bool FWeaponSlot::AddWeapon(PClassActor *type) { unsigned int i; - if (type == NULL) + if (type == nullptr) { return false; } @@ -595,10 +564,10 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) Clear(); } tok = strtok(buff, " "); - while (tok != NULL) + while (tok != nullptr) { AddWeapon(tok); - tok = strtok(NULL, " "); + tok = strtok(nullptr, " "); } } @@ -611,7 +580,7 @@ void FWeaponSlot :: AddWeaponList(const char *list, bool clear) // //=========================================================================== -int FWeaponSlot::LocateWeapon(PClassWeapon *type) +int FWeaponSlot::LocateWeapon(PClassActor *type) { unsigned int i; @@ -642,22 +611,22 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { int i, j; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } // Does this slot even have any weapons? if (Weapons.Size() == 0) { return player->ReadyWeapon; } - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { for (i = 0; (unsigned)i < Weapons.Size(); i++) { if (Weapons[i].Type == player->ReadyWeapon->GetClass() || (player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP && - player->ReadyWeapon->SisterWeapon != NULL && + player->ReadyWeapon->SisterWeapon != nullptr && player->ReadyWeapon->SisterWeapon->GetClass() == Weapons[i].Type)) { for (j = (i == 0 ? Weapons.Size() - 1 : i - 1); @@ -666,7 +635,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[j].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -681,7 +650,7 @@ AWeapon *FWeaponSlot::PickWeapon(player_t *player, bool checkammo) { AWeapon *weap = static_cast (player->mo->FindInventory(Weapons[i].Type)); - if (weap != NULL && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) + if (weap != nullptr && weap->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (!checkammo || weap->CheckAmmo(AWeapon::EitherFire, false)) { @@ -737,7 +706,7 @@ void FWeaponSlot::Sort() for (i = 1; i < (int)Weapons.Size(); ++i) { int pos = Weapons[i].Position; - PClassWeapon *type = Weapons[i].Type; + PClassActor *type = Weapons[i].Type; for (j = i - 1; j >= 0 && Weapons[j].Position > pos; --j) { Weapons[j + 1] = Weapons[j]; @@ -786,7 +755,7 @@ void FWeaponSlots::Clear() // //=========================================================================== -ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) +ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassActor *type) { int currSlot, index; @@ -811,7 +780,7 @@ ESlotDef FWeaponSlots::AddDefaultWeapon (int slot, PClassWeapon *type) // //=========================================================================== -bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const index) +bool FWeaponSlots::LocateWeapon (PClassActor *type, int *const slot, int *const index) { int i, j; @@ -820,8 +789,8 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const j = Slots[i].LocateWeapon(type); if (j >= 0) { - if (slot != NULL) *slot = i; - if (index != NULL) *index = j; + if (slot != nullptr) *slot = i; + if (index != nullptr) *index = j; return true; } } @@ -858,14 +827,14 @@ static bool FindMostRecentWeapon(player_t *player, int *slot, int *index) { return player->weapons.LocateWeapon(player->PendingWeapon->GetClass(), slot, index); } - else if (player->ReadyWeapon != NULL) + else if (player->ReadyWeapon != nullptr) { AWeapon *weap = player->ReadyWeapon; if (!player->weapons.LocateWeapon(weap->GetClass(), slot, index)) { // If the current weapon wasn't found and is powered up, // look for its non-powered up version. - if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != NULL) + if (weap->WeaponFlags & WIF_POWERED_UP && weap->SisterWeaponType != nullptr) { return player->weapons.LocateWeapon(weap->SisterWeaponType, slot, index); } @@ -894,16 +863,16 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon(player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon(player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = NUM_WEAPON_SLOTS - 1; startindex = Slots[startslot].Size() - 1; @@ -922,9 +891,9 @@ AWeapon *FWeaponSlots::PickNextWeapon(player_t *player) slot = 0; } } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -949,16 +918,16 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) int startslot, startindex; int slotschecked = 0; - if (player->mo == NULL) + if (player->mo == nullptr) { - return NULL; + return nullptr; } - if (player->ReadyWeapon == NULL || FindMostRecentWeapon (player, &startslot, &startindex)) + if (player->ReadyWeapon == nullptr || FindMostRecentWeapon (player, &startslot, &startindex)) { int slot; int index; - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { startslot = 0; startindex = 0; @@ -977,9 +946,9 @@ AWeapon *FWeaponSlots::PickPrevWeapon (player_t *player) } index = Slots[slot].Size() - 1; } - PClassWeapon *type = Slots[slot].GetWeapon(index); + PClassActor *type = Slots[slot].GetWeapon(index); AWeapon *weap = static_cast(player->mo->FindInventory(type)); - if (weap != NULL && weap->CheckAmmo(AWeapon::EitherFire, false)) + if (weap != nullptr && weap->CheckAmmo(AWeapon::EitherFire, false)) { return weap; } @@ -1011,23 +980,23 @@ void FWeaponSlots::AddExtraWeapons() // Append extra weapons to the slots. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - PClass *cls = PClassActor::AllActorClasses[i]; + PClassActor *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { continue; } - PClassWeapon *acls = static_cast(cls); - if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && - acls->Replacement == NULL && // Replaced weapons don't get slotted. - !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && - !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. + auto weapdef = ((AWeapon*)GetDefaultByType(cls)); + if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + cls->Replacement == nullptr && // Replaced weapons don't get slotted. + !(weapdef->WeaponFlags & WIF_POWERED_UP) && + !LocateWeapon(cls, nullptr, nullptr) // Don't duplicate it if it's already present. ) { - int slot = acls->SlotNumber; + int slot = weapdef->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { - FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; + FWeaponSlot::WeaponInfo info = { cls, weapdef->SlotPriority }; Slots[slot].Weapons.Push(info); } } @@ -1064,8 +1033,8 @@ void FWeaponSlots::SetFromGameInfo() { for (unsigned j = 0; j < gameinfo.DefaultWeaponSlots[i].Size(); j++) { - PClassWeapon *cls = dyn_cast(PClass::FindClass(gameinfo.DefaultWeaponSlots[i][j])); - if (cls == NULL) + PClassActor *cls = PClass::FindActor(gameinfo.DefaultWeaponSlots[i][j]); + if (cls == nullptr) { Printf("Unknown weapon class '%s' found in default weapon slot assignments\n", gameinfo.DefaultWeaponSlots[i][j].GetChars()); @@ -1261,7 +1230,7 @@ CCMD (setslot) if (argv.argc() < 2 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) { Printf("Usage: setslot [slot] [weapons]\nCurrent slot assignments:\n"); - if (players[consoleplayer].mo != NULL) + if (players[consoleplayer].mo != nullptr) { FString config(GameConfig->GetConfigPath(false)); Printf(TEXTCOLOR_BLUE "Add the following to " TEXTCOLOR_ORANGE "%s" TEXTCOLOR_BLUE @@ -1280,7 +1249,7 @@ CCMD (setslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->Slots[slot].Clear(); for (int i = 2; i < argv.argc(); ++i) @@ -1300,7 +1269,7 @@ CCMD (setslot) Net_WriteByte(argv.argc()-2); for (int i = 2; i < argv.argc(); i++) { - Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); + Net_WriteWeapon(dyn_cast(PClass::FindClass(argv[i]))); } } } @@ -1311,9 +1280,9 @@ CCMD (setslot) // //=========================================================================== -void FWeaponSlots::AddSlot(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlot(int slot, PClassActor *type, bool feedback) { - if (type != NULL && !Slots[slot].AddWeapon(type) && feedback) + if (type != nullptr && !Slots[slot].AddWeapon(type) && feedback) { Printf ("Could not add %s to slot %d\n", type->TypeName.GetChars(), slot); } @@ -1329,8 +1298,8 @@ CCMD (addslot) return; } - PClassWeapon *type= dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + PClassActor *type= dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf("%s is not a weapon\n", argv[2]); return; @@ -1340,7 +1309,7 @@ CCMD (addslot) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlot(int(slot), type, false); } @@ -1371,9 +1340,9 @@ CCMD (weaponsection) // CCMD addslotdefault // //=========================================================================== -void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) +void FWeaponSlots::AddSlotDefault(int slot, PClassActor *type, bool feedback) { - if (type != NULL && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + if (type != nullptr && type->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { switch (AddDefaultWeapon(slot, type)) { @@ -1396,7 +1365,7 @@ void FWeaponSlots::AddSlotDefault(int slot, PClassWeapon *type, bool feedback) CCMD (addslotdefault) { - PClassWeapon *type; + PClassActor *type; unsigned int slot; if (argv.argc() != 3 || (slot = atoi (argv[1])) >= NUM_WEAPON_SLOTS) @@ -1405,8 +1374,8 @@ CCMD (addslotdefault) return; } - type = dyn_cast(PClass::FindClass(argv[2])); - if (type == NULL) + type = dyn_cast(PClass::FindClass(argv[2])); + if (type == nullptr) { Printf ("%s is not a weapon\n", argv[2]); return; @@ -1416,7 +1385,7 @@ CCMD (addslotdefault) { KeyConfWeapons.Push(argv.args()); } - else if (PlayingKeyConf != NULL) + else if (PlayingKeyConf != nullptr) { PlayingKeyConf->AddSlotDefault(int(slot), type, false); } @@ -1444,7 +1413,7 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) FString cmd(KeyConfWeapons[i]); AddCommandString(cmd.LockBuffer()); } - PlayingKeyConf = NULL; + PlayingKeyConf = nullptr; } //=========================================================================== @@ -1461,20 +1430,20 @@ void P_PlaybackKeyConfWeapons(FWeaponSlots *slots) void P_SetupWeapons_ntohton() { unsigned int i; - PClassWeapon *cls; + PClassActor *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); - cls = NULL; - Weapons_ntoh.Push(cls); // Index 0 is always NULL. + cls = nullptr; + Weapons_ntoh.Push(cls); // Index 0 is always nullptr. for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { - Weapons_ntoh.Push(static_cast(cls)); + Weapons_ntoh.Push(static_cast(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); @@ -1500,8 +1469,8 @@ void P_SetupWeapons_ntohton() static int ntoh_cmp(const void *a, const void *b) { - PClassWeapon *c1 = *(PClassWeapon **)a; - PClassWeapon *c2 = *(PClassWeapon **)b; + PClassActor *c1 = *(PClassActor **)a; + PClassActor *c2 = *(PClassActor **)b; int g1 = c1->GameFilter == GAME_Any ? 1 : (c1->GameFilter & gameinfo.gametype) ? 0 : 2; int g2 = c2->GameFilter == GAME_Any ? 1 : (c2->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) @@ -1541,24 +1510,24 @@ void P_WriteDemoWeaponsChunk(BYTE **demo) void P_ReadDemoWeaponsChunk(BYTE **demo) { int count, i; - PClassWeapon *type; + PClassActor *type; const char *s; count = ReadWord(demo); Weapons_ntoh.Resize(count); Weapons_hton.Clear(count); - Weapons_ntoh[0] = type = NULL; + Weapons_ntoh[0] = type = nullptr; Weapons_hton[type] = 0; for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = dyn_cast(PClass::FindClass(s)); + type = dyn_cast(PClass::FindClass(s)); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; - if (type != NULL) + if (type != nullptr) { Weapons_hton[type] = i; } @@ -1571,12 +1540,12 @@ void P_ReadDemoWeaponsChunk(BYTE **demo) // //=========================================================================== -void Net_WriteWeapon(PClassWeapon *type) +void Net_WriteWeapon(PClassActor *type) { int index, *index_p; index_p = Weapons_hton.CheckKey(type); - if (index_p == NULL) + if (index_p == nullptr) { index = 0; } @@ -1603,7 +1572,7 @@ void Net_WriteWeapon(PClassWeapon *type) // //=========================================================================== -PClassWeapon *Net_ReadWeapon(BYTE **stream) +PClassActor *Net_ReadWeapon(BYTE **stream) { int index; @@ -1614,7 +1583,7 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) } if ((unsigned)index >= Weapons_ntoh.Size()) { - return NULL; + return nullptr; } return Weapons_ntoh[index]; } diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index b2eeaf9514..50862bc470 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -1,7 +1,7 @@ #pragma once #include "a_pickups.h" -class PClassWeapon; +class PClassActor; class AWeapon; class FWeaponSlot @@ -12,13 +12,13 @@ public: FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } void Clear() { Weapons.Clear(); } bool AddWeapon (const char *type); - bool AddWeapon (PClassWeapon *type); + bool AddWeapon (PClassActor *type); void AddWeaponList (const char *list, bool clear); AWeapon *PickWeapon (player_t *player, bool checkammo = false); int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassWeapon *type); + int LocateWeapon (PClassActor *type); - inline PClassWeapon *GetWeapon (int index) const + inline PClassActor *GetWeapon (int index) const { if ((unsigned)index < Weapons.Size()) { @@ -35,7 +35,7 @@ public: private: struct WeaponInfo { - PClassWeapon *Type; + PClassActor *Type; int Position; }; void SetInitialPositions(); @@ -61,8 +61,8 @@ struct FWeaponSlots AWeapon *PickPrevWeapon (player_t *player); void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + bool LocateWeapon (PClassActor *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassActor *type); void AddExtraWeapons(); void SetFromGameInfo(); void SetFromPlayer(PClassPlayerPawn *type); @@ -72,36 +72,23 @@ struct FWeaponSlots int RestoreSlots (FConfigFile *config, const char *section); void PrintSettings(); - void AddSlot(int slot, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + void AddSlot(int slot, PClassActor *type, bool feedback); + void AddSlotDefault(int slot, PClassActor *type, bool feedback); }; void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); +void Net_WriteWeapon(PClassActor *type); +PClassActor *Net_ReadWeapon(BYTE **stream); void P_SetupWeapons_ntohton(); void P_WriteDemoWeaponsChunk(BYTE **demo); void P_ReadDemoWeaponsChunk(BYTE **demo); -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - - int SlotNumber; - int SlotPriority; -}; - class AWeapon : public AStateProvider { - DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + DECLARE_CLASS(AWeapon, AStateProvider) HAS_OBJECT_POINTERS public: DWORD WeaponFlags; @@ -112,7 +99,7 @@ public: int Kickback; float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *SisterWeaponType; // Another weapon to pick up with this one PClassActor *ProjectileType; // Projectile used by primary attack PClassActor *AltProjectileType; // Projectile used by alternate attack int SelectionOrder; // Lower-numbered weapons get picked first @@ -122,6 +109,8 @@ public: int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + int SlotNumber; + int SlotPriority; // In-inventory instance variables TObjPtr Ammo1, Ammo2; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 4822a27b3e..859ccb3f5e 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -2065,8 +2065,7 @@ DEFINE_CLASS_PROPERTY(bobrangey, F, Weapon) DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) { PROP_INT_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotNumber = i; + defaults->SlotNumber = i; } //========================================================================== @@ -2075,8 +2074,7 @@ DEFINE_CLASS_PROPERTY(slotnumber, I, Weapon) DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassWeapon))); - static_cast(info)->SlotPriority = int(i*65536); + defaults->SlotPriority = int(i*65536); } //========================================================================== diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 5634c4c497..7bda52e528 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -43,6 +43,8 @@ class Weapon : StateProvider native Weapon.BobSpeed 1.0; Weapon.BobRangeX 1.0; Weapon.BobRangeY 1.0; + Weapon.SlotNumber -1; + Weapon.SlotPriority 32767; +WEAPONSPAWN DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; } From e3d07bddabfee6f6d13badbeb8baeb403c01a7f3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 20:25:52 +0100 Subject: [PATCH 5/6] - moved the TypeTableType pointer from PClassType to PType. Removing this variable is needed to remove PClassType and PClassClass as the next step to eliminate all of PClass's subclasses in order to clean up the type system. --- src/dobjtype.cpp | 97 ++++++++++++++---------------------------------- src/dobjtype.h | 4 +- 2 files changed, 29 insertions(+), 72 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index d5653fc6d8..0e7a5e304f 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -162,23 +162,9 @@ IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== PClassType::PClassType() -: TypeTableType(nullptr) { } -//========================================================================== -// -// PClassType :: DeriveData -// -//========================================================================== - -void PClassType::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); - Super::DeriveData(newclass); - static_cast(newclass)->TypeTableType = TypeTableType; -} - /* PClassClass ************************************************************/ IMPLEMENT_CLASS(PClassClass, false, false) @@ -187,14 +173,10 @@ IMPLEMENT_CLASS(PClassClass, false, false) // // PClassClass Constructor // -// The only thing we want to do here is automatically set TypeTableType -// to PClass. -// //========================================================================== PClassClass::PClassClass() { - TypeTableType = RUNTIME_CLASS(PClass); } /* PType ******************************************************************/ @@ -383,40 +365,10 @@ const char *PType::DescriptiveName() const // // PType :: StaticInit STATIC // -// Set up TypeTableType values for every PType child and create basic types. -// //========================================================================== void PType::StaticInit() { - // Add types to the global symbol table. - - // Set up TypeTable hash keys. - RUNTIME_CLASS(PErrorType)->TypeTableType = RUNTIME_CLASS(PErrorType); - RUNTIME_CLASS(PVoidType)->TypeTableType = RUNTIME_CLASS(PVoidType); - RUNTIME_CLASS(PInt)->TypeTableType = RUNTIME_CLASS(PInt); - RUNTIME_CLASS(PBool)->TypeTableType = RUNTIME_CLASS(PBool); - RUNTIME_CLASS(PFloat)->TypeTableType = RUNTIME_CLASS(PFloat); - RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); - RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); - RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); - RUNTIME_CLASS(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); - RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); - RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); - RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); - RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); - RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); - RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); - RUNTIME_CLASS(PResizableArray)->TypeTableType = RUNTIME_CLASS(PResizableArray); - RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); - RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); - RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); - RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); - RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); - RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); - RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); - // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); TypeTable.AddType(TypeAuto = new PErrorType(2)); @@ -1503,13 +1455,18 @@ void PPointer::SetPointer(void *base, unsigned offset, TArray *special) void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - ar(key, *(PClass **)addr); - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - ar(key, *(DObject **)addr); + auto pt = static_cast(PointedType); + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ar(key, *(PClass **)addr); + } + else + { + ar(key, *(DObject **)addr); + } } else { @@ -1526,16 +1483,19 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { - if (PointedType->IsKindOf(RUNTIME_CLASS(PClassClass))) + if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - bool res = false; - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return res; - } - else if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - bool res = false; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + auto pt = static_cast(PointedType); + bool res = true; + + if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) + { + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + } + else + { + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + } return res; } return false; @@ -3071,8 +3031,6 @@ void PClass::StaticBootstrap() // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. - clscls->TypeTableType = cls; - cls->TypeTableType = cls; clscls->InsertIntoHash(); cls->InsertIntoHash(); @@ -3794,7 +3752,7 @@ PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, si } for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) { - if (type->GetClass()->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) { return type; } @@ -3837,10 +3795,10 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t { #ifdef _DEBUG size_t bucketcheck; - assert(metatype == type->GetClass()->TypeTableType && "Metatype does not match passed object"); assert(FindType(metatype, parm1, parm2, &bucketcheck) == nullptr && "Type must not be inserted more than once"); assert(bucketcheck == bucket && "Passed bucket was wrong"); #endif + type->TypeTableType = metatype; type->HashNext = TypeHash[bucket]; TypeHash[bucket] = type; GC::WriteBarrier(type); @@ -3854,11 +3812,12 @@ void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t void FTypeTable::AddType(PType *type) { - PClass *metatype; intptr_t parm1, parm2; size_t bucket; - metatype = type->GetClass()->TypeTableType; + // Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless. + type->TypeTableType = type->GetClass(); + PClass *metatype = type->TypeTableType; type->GetTypeIDs(parm1, parm2); bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; assert(FindType(metatype, parm1, parm2, nullptr) == nullptr && "Type must not be inserted more than once"); diff --git a/src/dobjtype.h b/src/dobjtype.h index 3e204da62b..02877a4ec4 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -215,6 +215,7 @@ public: typedef PClassType MetaClass; MetaClass *GetClass() const; + PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment PType *HashNext; // next type in this type table @@ -875,9 +876,6 @@ class PClassType : public PClass protected: public: PClassType(); - virtual void DeriveData(PClass *newclass); - - PClass *TypeTableType; // The type to use for hashing into the type table }; inline PType::MetaClass *PType::GetClass() const From 3cddcc852445bc72dc2216950cb5a8d62abd0f13 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Feb 2017 20:45:56 +0100 Subject: [PATCH 6/6] - removed PClassType and PClassClass. All non-actors now use PClass exclusively as their type descriptor. Getting rid of these two classes already removes a lot of obtuse code from the type system, but there's still three more classes to go before a major cleanup can be undertaken. --- src/dobject.h | 2 -- src/dobjtype.cpp | 41 +---------------------------------------- src/dobjtype.h | 39 --------------------------------------- 3 files changed, 1 insertion(+), 81 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 1a7afaea00..ef75609095 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -95,8 +95,6 @@ enum CLASSREG_PClassActor, CLASSREG_PClassInventory, CLASSREG_PClassPlayerPawn, - CLASSREG_PClassType, - CLASSREG_PClassClass, }; struct ClassReg diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0e7a5e304f..54cc646756 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -151,34 +151,6 @@ void DumpTypeTable() Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); } -/* PClassType *************************************************************/ - -IMPLEMENT_CLASS(PClassType, false, false) - -//========================================================================== -// -// PClassType Constructor -// -//========================================================================== - -PClassType::PClassType() -{ -} - -/* PClassClass ************************************************************/ - -IMPLEMENT_CLASS(PClassClass, false, false) - -//========================================================================== -// -// PClassClass Constructor -// -//========================================================================== - -PClassClass::PClassClass() -{ -} - /* PType ******************************************************************/ IMPLEMENT_CLASS(PType, true, true) @@ -3014,28 +2986,19 @@ void PClass::StaticShutdown () // // PClass :: StaticBootstrap STATIC // -// PClass and PClassClass have intermingling dependencies on their -// definitions. To sort this out, we explicitly define them before -// proceeding with the RegisterClass loop in StaticInit(). -// //========================================================================== void PClass::StaticBootstrap() { - PClassClass *clscls = new PClassClass; - PClassClass::RegistrationInfo.SetupClass(clscls); - - PClassClass *cls = new PClassClass; + PClass *cls = new PClass; PClass::RegistrationInfo.SetupClass(cls); // The PClassClass constructor initialized these to nullptr, because the // PClass metadata had not been created yet. Now it has, so we know what // they should be and can insert them into the type table successfully. - clscls->InsertIntoHash(); cls->InsertIntoHash(); // Create parent objects before we go so that these definitions are complete. - clscls->ParentClass = PClassType::RegistrationInfo.ParentType->RegisterClass(); cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); } @@ -3095,8 +3058,6 @@ PClass *ClassReg::RegisterClass() &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, - &PClassType::RegistrationInfo, - &PClassClass::RegistrationInfo, }; // Skip classes that have already been registered diff --git a/src/dobjtype.h b/src/dobjtype.h index 02877a4ec4..3858585e92 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -199,22 +199,13 @@ public: // Prototype *+ *+ struct ZCC_ExprConstant; -class PClassType; class PType : public PTypeBase { - //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); - // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, - // and we can't define it until we've defined PClass. But we can't define that - // without defining PType. DECLARE_ABSTRACT_CLASS(PType, PTypeBase) HAS_OBJECT_POINTERS; protected: - enum { MetaClassNum = CLASSREG_PClassType }; public: - typedef PClassType MetaClass; - MetaClass *GetClass() const; - PClass *TypeTableType; // The type to use for hashing into the type table unsigned int Size; // this type's size unsigned int Align; // this type's preferred alignment @@ -777,22 +768,17 @@ enum TentativeClass = UINT_MAX, }; -class PClassClass; class PClass : public PNativeStruct { DECLARE_CLASS(PClass, PNativeStruct); HAS_OBJECT_POINTERS; protected: // We unravel _WITH_META here just as we did for PType. - enum { MetaClassNum = CLASSREG_PClassClass }; TArray SpecialInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: - typedef PClassClass MetaClass; - MetaClass *GetClass() const; - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -870,31 +856,6 @@ public: static bool bVMOperational; }; -class PClassType : public PClass -{ - DECLARE_CLASS(PClassType, PClass); -protected: -public: - PClassType(); -}; - -inline PType::MetaClass *PType::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - -class PClassClass : public PClassType -{ - DECLARE_CLASS(PClassClass, PClassType); -public: - PClassClass(); -}; - -inline PClass::MetaClass *PClass::GetClass() const -{ - return static_cast(DObject::GetClass()); -} - // Type tables -------------------------------------------------------------- struct FTypeTable