From 311ce2362ac73b0a801948fa663fe31a50088629 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Apr 2017 19:37:56 +0200 Subject: [PATCH 01/24] - started moving stuff out of PClassActor into meta data. This reinstates the old FActorInfo as part of the meta data a class can have so that the class descriptor itself can be freed from any data not directly relevant for managing the class's type information. --- src/actor.h | 6 ++ src/d_dehacked.cpp | 8 +-- src/g_inventory/a_weapons.cpp | 2 +- src/g_shared/a_dynlightdata.cpp | 4 +- src/info.cpp | 80 +++++++++++++++++++---- src/info.h | 21 +++++- src/scripting/decorate/thingdef_parse.cpp | 1 - src/scripting/zscript/zcc_compile.cpp | 9 ++- 8 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/actor.h b/src/actor.h index 631d854d0..a856103dd 100644 --- a/src/actor.h +++ b/src/actor.h @@ -612,6 +612,12 @@ public: return (AActor *)(this->GetClass()->Defaults); } + FActorInfo *GetInfo() const + { + return ((PClassActor*)GetClass())->ActorInfo(); + } + + FDropItem *GetDropItems() const; // Return true if the monster should use a missile attack, false for melee diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 411564851..b050bd48c 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3051,15 +3051,15 @@ void FinishDehPatch () // Use the DECORATE replacement feature to redirect all spawns // of the original class to the new one. - PClassActor *old_replacement = type->Replacement; + PClassActor *old_replacement = type->ActorInfo()->Replacement; - type->Replacement = subclass; - subclass->Replacee = type; + type->ActorInfo()->Replacement = subclass; + subclass->ActorInfo()->Replacee = type; // If this actor was already replaced by another actor, copy that // replacement over to this item. if (old_replacement != NULL) { - subclass->Replacement = old_replacement; + subclass->ActorInfo()->Replacement = old_replacement; } DPrintf (DMSG_NOTIFY, "%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars()); diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index af9634846..89c1f00e5 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -986,7 +986,7 @@ void FWeaponSlots::AddExtraWeapons() } auto weapdef = ((AWeapon*)GetDefaultByType(cls)); if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && - cls->Replacement == nullptr && // Replaced weapons don't get slotted. + cls->ActorInfo()->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. ) diff --git a/src/g_shared/a_dynlightdata.cpp b/src/g_shared/a_dynlightdata.cpp index 7db1f8f7c..757d26bf3 100644 --- a/src/g_shared/a_dynlightdata.cpp +++ b/src/g_shared/a_dynlightdata.cpp @@ -1058,7 +1058,7 @@ void InitializeActorLights() void *mem = ClassDataAllocator.Alloc(sizeof(FInternalLightAssociation)); FInternalLightAssociation * iasso = new(mem) FInternalLightAssociation(&LightAssociations[i]); if (iasso->Light() != nullptr) - ti->LightAssociations.Push(iasso); + ti->ActorInfo()->LightAssociations.Push(iasso); } } // we don't need the parser data for the light associations anymore @@ -1124,7 +1124,7 @@ void AActor::AttachLight(unsigned int count, const FLightDefaults *lightdef) void AActor::SetDynamicLights() { - TArray & LightAssociations = GetClass()->LightAssociations; + TArray & LightAssociations = GetInfo()->LightAssociations; unsigned int count = 0; if (state == NULL) return; diff --git a/src/info.cpp b/src/info.cpp index b8f7db995..f32baebc7 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -65,6 +65,62 @@ FRandom FState::pr_statetics("StateTics"); cycle_t ActionCycles; + +//========================================================================== +// +// special type for the native ActorInfo. This allows to let this struct +// be handled by the generic object constructors for the VM. +// +//========================================================================== + +class PActorInfo : public PBasicType +{ + DECLARE_CLASS(PActorInfo, PBasicType); +public: + PActorInfo() + :PBasicType(sizeof(FActorInfo), alignof(FActorInfo)) + { + } + + void SetDefaultValue(void *base, unsigned offset, TArray *special) const override + { + if (base != nullptr) new((uint8_t *)base + offset) FActorInfo; + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } + } + + void InitializeValue(void *addr, const void *def) const override + { + if (def == nullptr) + { + new(addr) FActorInfo; + } + else + { + new(addr) FActorInfo(*(const FActorInfo*)def); + } + } + + void DestroyValue(void *addr) const override + { + FActorInfo *self = (FActorInfo*)addr; + self->~FActorInfo(); + } + +}; + +IMPLEMENT_CLASS(PActorInfo, false, false) + +void AddActorInfo(PClass *cls) +{ + auto type = new PActorInfo; + TypeTable.AddType(type); + cls->AddField("*", type, VARF_Meta); +} + + void FState::SetAction(const char *name) { ActionFunc = FindVMFunction(RUNTIME_CLASS(AActor), name); @@ -245,8 +301,6 @@ PClassActor::PClassActor() DoomEdNum = -1; OwnedStates = NULL; NumOwnedStates = 0; - Replacement = NULL; - Replacee = NULL; StateList = NULL; DamageFactors = NULL; PainChances = NULL; @@ -339,8 +393,8 @@ bool PClassActor::SetReplacement(FName replaceName) } if (replacee != nullptr) { - replacee->Replacement = this; - Replacee = replacee; + replacee->ActorInfo()->Replacement = this; + ActorInfo()->Replacee = replacee; } } return true; @@ -467,15 +521,15 @@ PClassActor *PClassActor::GetReplacement(bool lookskill) lookskill = false; skillrepname = NAME_None; } } - if (Replacement == NULL && (!lookskill || skillrepname == NAME_None)) + auto Replacement = ActorInfo()->Replacement; + if (Replacement == nullptr && (!lookskill || skillrepname == NAME_None)) { return this; } // The Replacement field is temporarily NULLed to prevent // potential infinite recursion. - PClassActor *savedrep = Replacement; - Replacement = NULL; - PClassActor *rep = savedrep; + ActorInfo()->Replacement = nullptr; + PClassActor *rep = Replacement; // Handle skill-based replacement here. It has precedence on DECORATE replacement // in that the skill replacement is applied first, followed by DECORATE replacement // on the actor indicated by the skill replacement. @@ -487,7 +541,7 @@ PClassActor *PClassActor::GetReplacement(bool lookskill) // Skill replacements are not recursive, contrarily to DECORATE replacements rep = rep->GetReplacement(false); // Reset the temporarily NULLed field - Replacement = savedrep; + ActorInfo()->Replacement = Replacement; return rep; } @@ -523,21 +577,21 @@ PClassActor *PClassActor::GetReplacee(bool lookskill) lookskill = false; } } - if (Replacee == NULL && (!lookskill || skillrepname == NAME_None)) + PClassActor *savedrep = ActorInfo()->Replacee; + if (savedrep == nullptr && (!lookskill || skillrepname == NAME_None)) { return this; } // The Replacee field is temporarily NULLed to prevent // potential infinite recursion. - PClassActor *savedrep = Replacee; - Replacee = NULL; + ActorInfo()->Replacee = nullptr; PClassActor *rep = savedrep; if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != NULL)) { rep = PClass::FindActor(skillrepname); } rep = rep->GetReplacee(false); - Replacee = savedrep; + ActorInfo()->Replacee = savedrep; return rep; } diff --git a/src/info.h b/src/info.h index 5af8ac5f5..575f9318d 100644 --- a/src/info.h +++ b/src/info.h @@ -236,6 +236,19 @@ private: struct FDropItem; +struct FActorInfo +{ + TArray LightAssociations; + PClassActor *Replacement = nullptr; + PClassActor *Replacee = nullptr; + + FActorInfo() {} + FActorInfo(const FActorInfo & other) + { + LightAssociations = other.LightAssociations; + } +}; + class PClassActor : public PClass { DECLARE_CLASS(PClassActor, PClass); @@ -256,6 +269,11 @@ public: bool SetReplacement(FName replaceName); void SetDropItems(FDropItem *drops); + FActorInfo *ActorInfo() const + { + return (FActorInfo*)Meta; + } + FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); FState *FindState(FName name) const @@ -271,10 +289,7 @@ public: PClassActor *GetReplacement(bool lookskill=true); PClassActor *GetReplacee(bool lookskill=true); - TArray LightAssociations; FState *OwnedStates; - PClassActor *Replacement; - PClassActor *Replacee; int NumOwnedStates; uint8_t GameFilter; uint8_t DefaultStateUsage; // state flag defaults for blocks without a qualifier. diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 0bf96e441..edf46d3a7 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1016,7 +1016,6 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = DecoDerivedClass(sc, parent, typeName); ti->bDecorateClass = true; // we only set this for 'modern' DECORATE. The original stuff is so limited that it cannot do anything that may require flagging. - ti->Replacee = ti->Replacement = NULL; ti->DoomEdNum = -1; return ti; } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index fe93be7c9..454cab470 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1112,6 +1112,7 @@ ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expressio // builds the internal structure of all classes and structs // //========================================================================== +void AddActorInfo(PClass *cls); void ZCCCompiler::CompileAllFields() { @@ -1156,6 +1157,7 @@ void ZCCCompiler::CompileAllFields() for (unsigned i = 0; i < Classes.Size(); i++) { auto type = Classes[i]->Type(); + if (type->Size == TentativeClass) { if (type->ParentClass->Size == TentativeClass) @@ -1169,7 +1171,12 @@ void ZCCCompiler::CompileAllFields() type->Size = Classes[i]->Type()->ParentClass->Size; } } - if (Classes[i]->Type()->ParentClass) + if (type->TypeName == NAME_Actor) + { + assert(type->MetaSize == 0); + AddActorInfo(type); // AActor needs the actor info manually added to its meta data before adding any scripted fields. + } + else if (Classes[i]->Type()->ParentClass) type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize; else type->MetaSize = 0; From 05240ccbe57f89619f1fea4c8610728e3c5ecc5c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Apr 2017 21:48:41 +0200 Subject: [PATCH 02/24] - fixed redundant reallocation of constructable meta fields. - some optimization of access to OwnedStates in old DECORATE. - consolidate all places that print a state name into a subfunction. - allocate states from the ClassDataAllocator memory arena. States do not need to be freed separately from the rest of the static class data. --- src/dobjtype.cpp | 26 +++++- src/dobjtype.h | 1 + src/info.cpp | 4 - src/info.h | 1 + src/p_actionfunctions.cpp | 11 +-- src/p_mobj.cpp | 3 +- src/p_pspr.cpp | 15 ++-- src/p_states.cpp | 23 ++++-- src/scripting/decorate/olddecorations.cpp | 97 ++++++++++++----------- src/scripting/thingdef.cpp | 10 +-- 10 files changed, 106 insertions(+), 85 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b4fd9835d..c3932e068 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2888,6 +2888,12 @@ void PClass::StaticShutdown () p.PendingWeapon = nullptr; } + // This must be done before the type table is taken down. + for (auto cls : AllClasses) + { + Printf("Processing %s\n", cls->TypeName.GetChars()); + cls->DestroyMeta(cls->Meta); + } // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. bShutdown = true; TypeTable.Clear(); @@ -3162,8 +3168,6 @@ void PClass::InitializeSpecials(void *addr, void *defaults, TArrayDestroyMeta(addr); + for (auto tao : MetaInits) + { + tao.first->DestroyValue((uint8_t *)addr + tao.second); + } +} + //========================================================================== // // PClass :: Derive @@ -3265,7 +3286,6 @@ void PClass::InitializeDefaults() // Copy parent values from the parent defaults. assert(ParentClass != nullptr); if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); - if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); for (const PField *field : Fields) { if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) diff --git a/src/dobjtype.h b/src/dobjtype.h index bf6e9feb1..de364c4f8 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -634,6 +634,7 @@ public: void BuildArrayPointers(); void InitMeta(); void DestroySpecials(void *addr); + void DestroyMeta(void *addr); const PClass *NativeClass() const; // Returns true if this type is an ancestor of (or same as) the passed type. diff --git a/src/info.cpp b/src/info.cpp index f32baebc7..23c7fb7cc 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -318,10 +318,6 @@ PClassActor::PClassActor() PClassActor::~PClassActor() { - if (OwnedStates != NULL) - { - delete[] OwnedStates; - } if (DamageFactors != NULL) { delete DamageFactors; diff --git a/src/info.h b/src/info.h index 575f9318d..466e925cb 100644 --- a/src/info.h +++ b/src/info.h @@ -177,6 +177,7 @@ public: bool CallAction(AActor *self, AActor *stateowner, FStateParamInfo *stateinfo, FState **stateret); static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); + static FString StaticGetStateName(const FState *state); static FRandom pr_statetics; }; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 97be1b108..657a89bb3 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -130,8 +130,7 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) { if (!(state->UseFlags & SUF_ITEM)) { - auto so = FState::StaticFindStateOwner(state); - Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in CustomInventory state chains.\n", so->TypeName.GetChars(), int(state - so->OwnedStates)); + Printf(TEXTCOLOR_RED "State %s not flagged for use in CustomInventory state chains.\n", FState::StaticGetStateName(state)); return false; } @@ -144,8 +143,8 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(state); - Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), int(state - owner->OwnedStates), state->ActionFunc->PrintableName.GetChars()); + Printf(TEXTCOLOR_RED "Unsafe state call in state %s to %s which accesses user variables. The action function has been removed from this state\n", + FState::StaticGetStateName(state), state->ActionFunc->PrintableName.GetChars()); state->ActionFunc = nullptr; } @@ -188,9 +187,7 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) catch (CVMAbortException &err) { err.MaybePrintMessage(); - auto owner = FState::StaticFindStateOwner(state); - int offs = int(state - owner->OwnedStates); - err.stacktrace.AppendFormat("Called from state %s.%d in inventory state chain in %s\n", owner->TypeName.GetChars(), offs, GetClass()->TypeName.GetChars()); + err.stacktrace.AppendFormat("Called from state %s in inventory state chain in %s\n", FState::StaticGetStateName(state), GetClass()->TypeName.GetChars()); throw; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 6a543f091..0632ba20b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -632,8 +632,7 @@ bool AActor::SetState (FState *newstate, bool nofunction) } if (!(newstate->UseFlags & SUF_ACTOR)) { - auto so = FState::StaticFindStateOwner(newstate); - Printf(TEXTCOLOR_RED "State %s.%d in %s not flagged for use as an actor sprite\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates), GetClass()->TypeName.GetChars()); + Printf(TEXTCOLOR_RED "State %s in %s not flagged for use as an actor sprite\n", FState::StaticGetStateName(newstate), GetClass()->TypeName.GetChars()); state = nullptr; Destroy(); return false; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index c0e8a3a4b..959dbf220 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -350,8 +350,7 @@ void DPSprite::SetState(FState *newstate, bool pending) if (!(newstate->UseFlags & (SUF_OVERLAY|SUF_WEAPON))) // Weapon and overlay are mostly the same, the main difference is that weapon states restrict the self pointer to class Actor. { - auto so = FState::StaticFindStateOwner(newstate); - Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in overlays or weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); + Printf(TEXTCOLOR_RED "State %s not flagged for use in overlays or weapons\n", FState::StaticGetStateName(newstate)); State = nullptr; Destroy(); return; @@ -360,8 +359,7 @@ void DPSprite::SetState(FState *newstate, bool pending) { if (Caller->IsKindOf(NAME_Weapon)) { - auto so = FState::StaticFindStateOwner(newstate); - Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); + Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", FState::StaticGetStateName(newstate)); State = nullptr; Destroy(); return; @@ -414,9 +412,8 @@ void DPSprite::SetState(FState *newstate, bool pending) if (newstate->ActionFunc != nullptr && newstate->ActionFunc->Unsafe) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. - auto owner = FState::StaticFindStateOwner(newstate); - Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", - owner->TypeName.GetChars(), int(newstate - owner->OwnedStates), newstate->ActionFunc->PrintableName.GetChars()); + Printf(TEXTCOLOR_RED "Unsafe state call in state %sd to %s which accesses user variables. The action function has been removed from this state\n", + FState::StaticGetStateName(newstate), newstate->ActionFunc->PrintableName.GetChars()); newstate->ActionFunc = nullptr; } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) @@ -1512,11 +1509,11 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i PClassActor *cls = weapon->GetClass(); while (cls != RUNTIME_CLASS(AWeapon)) { - if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) + if (cls->OwnsState(flashstate)) { // The flash state belongs to this class. // Now let's check if the actually wanted state does also - if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + if (cls->OwnsState(flashstate + index)) { // we're ok so set the state P_SetPsprite(player, PSP_FLASH, flashstate + index, true); diff --git a/src/p_states.cpp b/src/p_states.cpp index 762a76896..731cbed9c 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -96,8 +96,7 @@ PClassActor *FState::StaticFindStateOwner (const FState *state) for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *info = PClassActor::AllActorClasses[i]; - if (state >= info->OwnedStates && - state < info->OwnedStates + info->NumOwnedStates) + if (info->OwnsState(state)) { return info; } @@ -117,8 +116,7 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf { while (info != NULL) { - if (state >= info->OwnedStates && - state < info->OwnedStates + info->NumOwnedStates) + if (info->OwnsState(state)) { return info; } @@ -127,6 +125,16 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf return NULL; } +//========================================================================== +// +// +//========================================================================== + +FString FState::StaticGetStateName(const FState *state) +{ + auto so = FState::StaticFindStateOwner(state); + return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->OwnedStates)); +} //========================================================================== // @@ -1000,7 +1008,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) if (count > 0) { - FState *realstates = new FState[count]; + FState *realstates = (FState*)ClassDataAllocator.Alloc(count * sizeof(FState)); int i; memcpy(realstates, &StateArray[0], count*sizeof(FState)); @@ -1071,8 +1079,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix) } else { - Printf(PRINT_LOG, "%s%s: %s.%d\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), - owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->OwnedStates)); + Printf(PRINT_LOG, "%s%s: %s\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(), FState::StaticGetStateName(StateList->Labels[i].State)); } } if (StateList->Labels[i].Children != NULL) @@ -1124,7 +1131,7 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo) { // Safely calculate the distance between two states. auto o1 = FState::StaticFindStateOwner(self); - if (other >= o1->OwnedStates && other < o1->OwnedStates + o1->NumOwnedStates) retv = int(other - self); + if (o1->OwnsState(other)) retv = int(other - self); } ACTION_RETURN_INT(retv); } diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 9ecf8c2a0..b9c618971 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -86,7 +86,7 @@ static const char *RenderStyles[] = "STYLE_Translucent", "STYLE_Add", //"STYLE_Shaded", - NULL + nullptr }; // CODE -------------------------------------------------------------------- @@ -158,66 +158,69 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) type->NumOwnedStates += 1; } - type->OwnedStates = new FState[type->NumOwnedStates]; - SaveStateSourceLines(type->OwnedStates, SourceLines); - memcpy (type->OwnedStates, &StateArray[0], type->NumOwnedStates * sizeof(type->OwnedStates[0])); + FState *states; + states = type->OwnedStates = (FState*)ClassDataAllocator.Alloc(type->NumOwnedStates * sizeof(FState)); + SaveStateSourceLines(states, SourceLines); + memcpy (states, &StateArray[0], type->NumOwnedStates * sizeof(states[0])); if (type->NumOwnedStates == 1) { - type->OwnedStates->Tics = -1; - type->OwnedStates->TicRange = 0; - type->OwnedStates->Misc1 = 0; + states->Tics = -1; + states->TicRange = 0; + states->Misc1 = 0; } else { size_t i; + // auto // Spawn states loop endlessly for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i) { - type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; + states[i].NextState = &states[i+1]; } - type->OwnedStates[i].NextState = &type->OwnedStates[extra.SpawnStart]; + states[i].NextState = &states[extra.SpawnStart]; // Death states are one-shot and freeze on the final state if (extra.DeathEnd != 0) { for (i = extra.DeathStart; i < extra.DeathEnd-1; ++i) { - type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; + states[i].NextState = &states[i+1]; } + FState *state = &states[i]; if (extra.bDiesAway || def == DEF_Projectile) { - type->OwnedStates[i].NextState = NULL; + state->NextState = nullptr; } else { - type->OwnedStates[i].Tics = -1; - type->OwnedStates[i].TicRange = 0; - type->OwnedStates[i].Misc1 = 0; + state->Tics = -1; + state->TicRange = 0; + state->Misc1 = 0; } if (def == DEF_Projectile) { if (extra.bExplosive) { - type->OwnedStates[extra.DeathStart].SetAction("A_Explode"); + states[extra.DeathStart].SetAction("A_Explode"); } } else { // The first frame plays the death sound and // the second frame makes it nonsolid. - type->OwnedStates[extra.DeathStart].SetAction("A_Scream"); + states[extra.DeathStart].SetAction("A_Scream"); if (extra.bSolidOnDeath) { } else if (extra.DeathStart + 1 < extra.DeathEnd) { - type->OwnedStates[extra.DeathStart+1].SetAction("A_NoBlocking"); + states[extra.DeathStart+1].SetAction("A_NoBlocking"); } else { - type->OwnedStates[extra.DeathStart].SetAction("A_ScreamAndUnblock"); + states[extra.DeathStart].SetAction("A_ScreamAndUnblock"); } if (extra.DeathHeight == 0) @@ -226,7 +229,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) } ((AActor*)(type->Defaults))->FloatVar("DeathHeight") = extra.DeathHeight; } - bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]); + bag.statedef.SetStateLabel("Death", &states[extra.DeathStart]); } // Burn states are the same as death states, except they can optionally terminate @@ -234,38 +237,39 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) { for (i = extra.FireDeathStart; i < extra.FireDeathEnd-1; ++i) { - type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; + states[i].NextState = &states[i+1]; } + FState *state = &states[i]; if (extra.bBurnAway) { - type->OwnedStates[i].NextState = NULL; + state->NextState = nullptr; } else { - type->OwnedStates[i].Tics = -1; - type->OwnedStates[i].TicRange = 0; - type->OwnedStates[i].Misc1 = 0; + state->Tics = -1; + state->TicRange = 0; + state->Misc1 = 0; } // The first frame plays the burn sound and // the second frame makes it nonsolid. - type->OwnedStates[extra.FireDeathStart].SetAction("A_ActiveSound"); + states[extra.FireDeathStart].SetAction("A_ActiveSound"); if (extra.bSolidOnBurn) { } else if (extra.FireDeathStart + 1 < extra.FireDeathEnd) { - type->OwnedStates[extra.FireDeathStart+1].SetAction("A_NoBlocking"); + states[extra.FireDeathStart+1].SetAction("A_NoBlocking"); } else { - type->OwnedStates[extra.FireDeathStart].SetAction("A_ActiveAndUnblock"); + states[extra.FireDeathStart].SetAction("A_ActiveAndUnblock"); } if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->Height; ((AActor*)(type->Defaults))->FloatVar("BurnHeight") = extra.BurnHeight; - bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]); + bag.statedef.SetStateLabel("Burn", &states[extra.FireDeathStart]); } // Ice states are similar to burn and death, except their final frame enters @@ -274,21 +278,22 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) { for (i = extra.IceDeathStart; i < extra.IceDeathEnd-1; ++i) { - type->OwnedStates[i].NextState = &type->OwnedStates[i+1]; + states[i].NextState = &states[i+1]; } - type->OwnedStates[i].NextState = &type->OwnedStates[type->NumOwnedStates-1]; - type->OwnedStates[i].Tics = 5; - type->OwnedStates[i].TicRange = 0; - type->OwnedStates[i].Misc1 = 0; - type->OwnedStates[i].SetAction("A_FreezeDeath"); + FState *state = &states[i]; + state->NextState = &states[type->NumOwnedStates-1]; + state->Tics = 5; + state->TicRange = 0; + state->Misc1 = 0; + state->SetAction("A_FreezeDeath"); i = type->NumOwnedStates - 1; - type->OwnedStates[i].NextState = &type->OwnedStates[i]; - type->OwnedStates[i].Tics = 1; - type->OwnedStates[i].TicRange = 0; - type->OwnedStates[i].Misc1 = 0; - type->OwnedStates[i].SetAction("A_FreezeDeathChunks"); - bag.statedef.SetStateLabel("Ice", &type->OwnedStates[extra.IceDeathStart]); + state->NextState = &states[i]; + state->Tics = 1; + state->TicRange = 0; + state->Misc1 = 0; + state->SetAction("A_FreezeDeathChunks"); + bag.statedef.SetStateLabel("Ice", &states[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) { @@ -303,7 +308,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) { ((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE; } - bag.statedef.SetStateLabel("Spawn", &type->OwnedStates[extra.SpawnStart]); + bag.statedef.SetStateLabel("Spawn", &states[extra.SpawnStart]); bag.statedef.InstallStates (type, ((AActor *)(type->Defaults))); } @@ -558,11 +563,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, } else if (sc.String[0] != '*') { - HandleActorFlag(sc, bag, sc.String, NULL, '+'); + HandleActorFlag(sc, bag, sc.String, nullptr, '+'); } else { - sc.ScriptError (NULL); + sc.ScriptError (nullptr); } sc.MustGetString (); } @@ -621,7 +626,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray memset (&state, 0, sizeof(state)); state.UseFlags = info->DefaultStateUsage; - while (token != NULL) + while (token != nullptr) { // Skip leading white space while (*token == ' ') @@ -631,7 +636,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray bool firstState = true; char *colon = strchr (token, ':'); - if (colon != NULL) + if (colon != nullptr) { char *stop; @@ -682,7 +687,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray SourceLines.Push(sc); } - token = strtok (NULL, ",\t\n\r"); + token = strtok (nullptr, ",\t\n\r"); } } diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index a8503e64e..0cb25b1c2 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -282,9 +282,8 @@ static void CheckForUnsafeStates(PClassActor *obj) if (state->ActionFunc && state->ActionFunc->Unsafe) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. - auto owner = FState::StaticFindStateOwner(state); - GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "Unsafe state call in state %s.%d which accesses user variables, reached by %s.%s.\n", - owner->TypeName.GetChars(), int(state - owner->OwnedStates), obj->TypeName.GetChars(), FName(*test).GetChars()); + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "Unsafe state call in state %s which accesses user variables, reached by %s.%s.\n", + FState::StaticGetStateName(state), obj->TypeName.GetChars(), FName(*test).GetChars()); } state = state->NextState; } @@ -308,9 +307,8 @@ static void CheckLabel(PClassActor *obj, FStateLabel *slb, int useflag, FName st { if (!(state->UseFlags & useflag)) { - auto owner = FState::StaticFindStateOwner(state); - GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "%s references state %s.%d as %s state, but this state is not flagged for use as %s.\n", - obj->TypeName.GetChars(), owner->TypeName.GetChars(), int(state - owner->OwnedStates), statename.GetChars(), descript); + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "%s references state %s as %s state, but this state is not flagged for use as %s.\n", + obj->TypeName.GetChars(), FState::StaticGetStateName(state), statename.GetChars(), descript); } } if (slb->Children != nullptr) From 4afe2d4218b311b2e6b856de2ed7ff822e4bbaf1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Apr 2017 22:44:35 +0200 Subject: [PATCH 03/24] - moved OwnedStates and NumOwnedStates out of PClassActor. --- src/d_dehacked.cpp | 2 +- src/gl/textures/gl_texture.cpp | 7 ++++--- src/info.cpp | 6 +----- src/info.h | 7 ++++--- src/p_actionfunctions.cpp | 4 ++-- src/p_states.cpp | 8 ++++---- src/scripting/backend/codegen.cpp | 10 +++++----- src/scripting/decorate/olddecorations.cpp | 16 +++++++--------- src/scripting/thingdef.cpp | 8 ++++---- src/serializer.cpp | 6 +++--- src/swrenderer/r_swrenderer.cpp | 4 ++-- 11 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index b050bd48c..affe344cb 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2843,7 +2843,7 @@ static bool LoadDehSupp () sc.MustGetStringName(","); sc.MustGetNumber(); - if (s.State == NULL || s.State + sc.Number > actortype->OwnedStates + actortype->NumOwnedStates) + if (s.State == NULL || !actortype->OwnsState(s.State + sc.Number)) { sc.ScriptError("Invalid state range in '%s'", type->TypeName.GetChars()); } diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index bef0da5d5..a7260879b 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -841,10 +841,11 @@ void gl_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl PClassActor *cls = pair->Key; int gltrans = GLTranslationPalette::GetInternalTranslation(GetDefaultByType(cls)->Translation); - for (int i = 0; i < cls->NumOwnedStates; i++) + for (int i = 0; i < cls->ActorInfo()->NumOwnedStates; i++) { - spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true); - FSpriteModelFrame * smf = gl_FindModelFrame(cls, cls->OwnedStates[i].sprite, cls->OwnedStates[i].Frame, false); + auto &state = cls->ActorInfo()->OwnedStates[i]; + spritelist[state.sprite].Insert(gltrans, true); + FSpriteModelFrame * smf = gl_FindModelFrame(cls, state.sprite, state.Frame, false); if (smf != NULL) { for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) diff --git a/src/info.cpp b/src/info.cpp index 23c7fb7cc..55369555f 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -162,15 +162,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, catch (CVMAbortException &err) { err.MaybePrintMessage(); - auto owner = FState::StaticFindStateOwner(this); - int offs = int(this - owner->OwnedStates); const char *callinfo = ""; if (info != nullptr && info->mStateType == STATE_Psprite) { if (stateowner->IsKindOf(NAME_Weapon) && stateowner != self) callinfo = "weapon "; else callinfo = "overlay "; } - err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); + err.stacktrace.AppendFormat("Called from %sstate %s in %s\n", callinfo, FState::StaticGetStateName(this), stateowner->GetClass()->TypeName.GetChars()); throw; throw; } @@ -299,8 +297,6 @@ PClassActor::PClassActor() GameFilter = GAME_Any; SpawnID = 0; DoomEdNum = -1; - OwnedStates = NULL; - NumOwnedStates = 0; StateList = NULL; DamageFactors = NULL; PainChances = NULL; diff --git a/src/info.h b/src/info.h index 466e925cb..935d62907 100644 --- a/src/info.h +++ b/src/info.h @@ -242,6 +242,8 @@ struct FActorInfo TArray LightAssociations; PClassActor *Replacement = nullptr; PClassActor *Replacee = nullptr; + FState *OwnedStates = nullptr; + int NumOwnedStates = 0; FActorInfo() {} FActorInfo(const FActorInfo & other) @@ -284,14 +286,13 @@ public: bool OwnsState(const FState *state) { - return state >= OwnedStates && state < OwnedStates + NumOwnedStates; + auto i = ActorInfo(); + return state >= i->OwnedStates && state < i->OwnedStates + i->NumOwnedStates; } PClassActor *GetReplacement(bool lookskill=true); PClassActor *GetReplacee(bool lookskill=true); - FState *OwnedStates; - int NumOwnedStates; uint8_t GameFilter; uint8_t DefaultStateUsage; // state flag defaults for blocks without a qualifier. uint16_t SpawnID; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 657a89bb3..5ffc88384 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -3317,9 +3317,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris) { mo->Translation = self->Translation; } - if (i < mo->GetClass()->NumOwnedStates) + if (i < mo->GetInfo()->NumOwnedStates) { - mo->SetState (mo->GetClass()->OwnedStates + i); + mo->SetState (mo->GetInfo()->OwnedStates + i); } mo->Vel.X = mult_h * pr_spawndebris.Random2() / 64.; mo->Vel.Y = mult_h * pr_spawndebris.Random2() / 64.; diff --git a/src/p_states.cpp b/src/p_states.cpp index 731cbed9c..b6593613a 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -133,7 +133,7 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf FString FState::StaticGetStateName(const FState *state) { auto so = FState::StaticFindStateOwner(state); - return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->OwnedStates)); + return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->ActorInfo()->OwnedStates)); } //========================================================================== @@ -816,7 +816,7 @@ void FStateDefinitions::FixStatePointers (PClassActor *actor, TArrayOwnedStates + v - 1; + list[i].State = actor->ActorInfo()->OwnedStates + v - 1; list[i].DefineFlags = SDF_STATE; } if (list[i].Children.Size() > 0) @@ -1012,8 +1012,8 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) int i; memcpy(realstates, &StateArray[0], count*sizeof(FState)); - actor->OwnedStates = realstates; - actor->NumOwnedStates = count; + actor->ActorInfo()->OwnedStates = realstates; + actor->ActorInfo()->NumOwnedStates = count; SaveStateSourceLines(realstates, SourceLines); // adjust the state pointers diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 4327bde9d..6b38999d3 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -10838,16 +10838,16 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) auto aclass = dyn_cast(ctx.Class); // This expression type can only be used from actors, for everything else it has already produced a compile error. - assert(aclass != nullptr && aclass->NumOwnedStates > 0); + assert(aclass != nullptr && aclass->ActorInfo()->NumOwnedStates > 0); - if (aclass->NumOwnedStates <= index) + if (aclass->ActorInfo()->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.Class->TypeName.GetChars(), index); delete this; return nullptr; } - int symlabel = StateLabels.AddPointer(aclass->OwnedStates + index); + int symlabel = StateLabels.AddPointer(aclass->ActorInfo()->OwnedStates + index); FxExpression *x = new FxConstant(symlabel, ScriptPosition); x->ValueType = TypeStateLabel; delete this; @@ -10912,8 +10912,8 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Index, ctx); } auto aclass = dyn_cast(ctx.Class); - assert(aclass != nullptr && aclass->NumOwnedStates > 0); - symlabel = StateLabels.AddPointer(aclass->OwnedStates + ctx.StateIndex); + assert(aclass != nullptr && aclass->ActorInfo()->NumOwnedStates > 0); + symlabel = StateLabels.AddPointer(aclass->ActorInfo()->OwnedStates + ctx.StateIndex); ValueType = TypeStateLabel; return this; } diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index b9c618971..3cf2c4f7d 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -130,8 +130,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) memset (&extra, 0, sizeof(extra)); ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc, StateArray, SourceLines); - bag.Info->NumOwnedStates = StateArray.Size(); - if (bag.Info->NumOwnedStates == 0) + if (StateArray.Size() == 0) { sc.ScriptError ("%s does not define any animation frames", typeName.GetChars() ); } @@ -155,14 +154,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) FScriptPosition icepos = SourceLines[extra.IceDeathEnd - 1]; StateArray.Push (icecopy); SourceLines.Push(icepos); - type->NumOwnedStates += 1; } FState *states; - states = type->OwnedStates = (FState*)ClassDataAllocator.Alloc(type->NumOwnedStates * sizeof(FState)); + states = type->ActorInfo()->OwnedStates = (FState*)ClassDataAllocator.Alloc(StateArray.Size() * sizeof(FState)); SaveStateSourceLines(states, SourceLines); - memcpy (states, &StateArray[0], type->NumOwnedStates * sizeof(states[0])); - if (type->NumOwnedStates == 1) + memcpy (states, &StateArray[0], StateArray.Size() * sizeof(states[0])); + if (StateArray.Size() == 1) { states->Tics = -1; states->TicRange = 0; @@ -171,7 +169,6 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) else { size_t i; - // auto // Spawn states loop endlessly for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i) @@ -281,13 +278,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) states[i].NextState = &states[i+1]; } FState *state = &states[i]; - state->NextState = &states[type->NumOwnedStates-1]; + state->NextState = &states[StateArray.Size() - 1]; state->Tics = 5; state->TicRange = 0; state->Misc1 = 0; state->SetAction("A_FreezeDeath"); - i = type->NumOwnedStates - 1; + i = StateArray.Size() - 1; state->NextState = &states[i]; state->Tics = 1; state->TicRange = 0; @@ -310,6 +307,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) } bag.statedef.SetStateLabel("Spawn", &states[extra.SpawnStart]); bag.statedef.InstallStates (type, ((AActor *)(type->Defaults))); + bag.Info->ActorInfo()->NumOwnedStates = StateArray.Size(); } //========================================================================== diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 0cb25b1c2..0b7e35aba 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -353,13 +353,13 @@ static void CheckStates(PClassActor *obj) { CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); } - for (int i = 0; i < obj->NumOwnedStates; i++) + for (int i = 0; i < obj->ActorInfo()->NumOwnedStates; i++) { - auto state = obj->OwnedStates + i; + auto state = obj->ActorInfo()->OwnedStates + i; if (state->NextState && (state->UseFlags & state->NextState->UseFlags) != state->UseFlags) { - GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "State %s.%d links to a state with incompatible restrictions.\n", - obj->TypeName.GetChars(), int(state - obj->OwnedStates)); + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "State %s links to a state with incompatible restrictions.\n", + FState::StaticGetStateName(state)); } } } diff --git a/src/serializer.cpp b/src/serializer.cpp index f514449ac..d5b3e286b 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -1877,7 +1877,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState { arc.w->StartArray(); arc.w->String(info->TypeName.GetChars()); - arc.w->Uint((uint32_t)(state - info->OwnedStates)); + arc.w->Uint((uint32_t)(state - info->ActorInfo()->OwnedStates)); arc.w->EndArray(); } else @@ -1908,9 +1908,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState if (cls.IsString() && ndx.IsUint()) { PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); - if (clas && ndx.GetUint() < (unsigned)clas->NumOwnedStates) + if (clas && ndx.GetUint() < (unsigned)clas->ActorInfo()->NumOwnedStates) { - state = clas->OwnedStates + ndx.GetUint(); + state = clas->ActorInfo()->OwnedStates + ndx.GetUint(); } else { diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index 0564dcfcf..11f4d801b 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -132,9 +132,9 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & { PClassActor *cls = pair->Key; - for (int i = 0; i < cls->NumOwnedStates; i++) + for (int i = 0; i < cls->ActorInfo()->NumOwnedStates; i++) { - spritelist[cls->OwnedStates[i].sprite] = true; + spritelist[cls->ActorInfo()->OwnedStates[i].sprite] = true; } } From 854053a14f58130f9f3d82d5f00d4c295af7a133 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Apr 2017 23:29:37 +0200 Subject: [PATCH 04/24] - use TArrays instead of TMaps to store damage factors and pain chances. For these fields maps have no advantage. Linearly searching a small array with up to 10 entries is nearly always faster than generating a hash for finding the entry in the map. --- src/d_dehacked.cpp | 2 +- src/dobject.cpp | 5 +- src/g_inventory/a_weapons.cpp | 7 +- src/info.cpp | 95 ++++++++++------------ src/info.h | 20 +++-- src/p_interaction.cpp | 10 +-- src/p_mobj.cpp | 8 +- src/scripting/decorate/olddecorations.cpp | 7 +- src/scripting/decorate/thingdef_parse.cpp | 4 +- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef_properties.cpp | 30 +++---- src/scripting/zscript/zcc_compile.cpp | 2 +- 12 files changed, 90 insertions(+), 102 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index affe344cb..da68bafe4 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -876,7 +876,7 @@ static int PatchThing (int thingy) else { info = GetDefaultByType (type); - ednum = &type->DoomEdNum; + ednum = &type->ActorInfo()->DoomEdNum; } } } diff --git a/src/dobject.cpp b/src/dobject.cpp index 456305f21..85e5697f6 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -98,9 +98,10 @@ CCMD (dumpactors) PClassActor *acls = dyn_cast(cls); if (acls != NULL) { + auto ainfo = acls->ActorInfo(); Printf("%s\t%i\t%i\t%s\t%s\n", - acls->TypeName.GetChars(), acls->DoomEdNum, - acls->SpawnID, filters[acls->GameFilter & 31], + acls->TypeName.GetChars(), ainfo->DoomEdNum, + ainfo->SpawnID, filters[ainfo->GameFilter & 31], acls->SourceLumpName.GetChars()); } else if (cls != NULL) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 89c1f00e5..c325a55ca 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -985,7 +985,8 @@ void FWeaponSlots::AddExtraWeapons() continue; } auto weapdef = ((AWeapon*)GetDefaultByType(cls)); - if ((cls->GameFilter == GAME_Any || (cls->GameFilter & gameinfo.gametype)) && + auto gf = cls->ActorInfo()->GameFilter; + if ((gf == GAME_Any || (gf & gameinfo.gametype)) && cls->ActorInfo()->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. @@ -1470,8 +1471,8 @@ static int ntoh_cmp(const void *a, const void *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; + int g1 = c1->ActorInfo()->GameFilter == GAME_Any ? 1 : (c1->ActorInfo()->GameFilter & gameinfo.gametype) ? 0 : 2; + int g2 = c2->ActorInfo()->GameFilter == GAME_Any ? 1 : (c2->ActorInfo()->GameFilter & gameinfo.gametype) ? 0 : 2; if (g1 != g2) { return g1 - g2; diff --git a/src/info.cpp b/src/info.cpp index 55369555f..203a60d7a 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -294,12 +294,7 @@ void PClassActor::StaticSetActorNums() PClassActor::PClassActor() { - GameFilter = GAME_Any; - SpawnID = 0; - DoomEdNum = -1; StateList = NULL; - DamageFactors = NULL; - PainChances = NULL; DropItems = NULL; // Record this in the master list. @@ -314,14 +309,6 @@ PClassActor::PClassActor() PClassActor::~PClassActor() { - if (DamageFactors != NULL) - { - delete DamageFactors; - } - if (PainChances != NULL) - { - delete PainChances; - } if (StateList != NULL) { StateList->Destroy(); @@ -340,26 +327,14 @@ void PClassActor::DeriveData(PClass *newclass) assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); PClassActor *newa = static_cast(newclass); - newa->DefaultStateUsage = DefaultStateUsage; newa->distancecheck = distancecheck; newa->DropItems = DropItems; newa->VisibleToPlayerClass = VisibleToPlayerClass; - if (DamageFactors != NULL) - { - // copy damage factors from parent - newa->DamageFactors = new DmgFactors; - *newa->DamageFactors = *DamageFactors; - } - if (PainChances != NULL) - { - // copy pain chances from parent - newa->PainChances = new PainChanceList; - *newa->PainChances = *PainChances; - } - + newa->DamageFactors = DamageFactors; + newa->PainChances = PainChances; newa->DisplayName = DisplayName; } @@ -450,16 +425,18 @@ void PClassActor::RegisterIDs() } // Conversation IDs have never been filtered by game so we cannot start doing that. + auto ConversationID = ActorInfo()->ConversationID; if (ConversationID > 0) { StrifeTypes[ConversationID] = cls; if (cls != this) { - Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); + Printf(TEXTCOLOR_RED"Conversation ID %d refers to hidden class type '%s'\n", ConversationID, cls->TypeName.GetChars()); } } - if (GameFilter == GAME_Any || (GameFilter & gameinfo.gametype)) + if (ActorInfo()->GameFilter == GAME_Any || (ActorInfo()->GameFilter & gameinfo.gametype)) { + auto SpawnID = ActorInfo()->SpawnID; if (SpawnID > 0) { SpawnableThings[SpawnID] = cls; @@ -468,6 +445,7 @@ void PClassActor::RegisterIDs() Printf(TEXTCOLOR_RED"Spawn ID %d refers to hidden class type '%s'\n", SpawnID, cls->TypeName.GetChars()); } } + auto DoomEdNum = ActorInfo()->DoomEdNum; if (DoomEdNum != -1) { FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum); @@ -602,11 +580,12 @@ DEFINE_ACTION_FUNCTION(AActor, GetReplacee) void PClassActor::SetDamageFactor(FName type, double factor) { - if (DamageFactors == NULL) + for (auto & p : DamageFactors) { - DamageFactors = new DmgFactors; + if (p.first == type) p.second = factor; + return; } - DamageFactors->Insert(type, factor); + DamageFactors.Push({ type, factor }); } //========================================================================== @@ -617,17 +596,15 @@ void PClassActor::SetDamageFactor(FName type, double factor) void PClassActor::SetPainChance(FName type, int chance) { + for (auto & p : PainChances) + { + if (p.first == type) p.second = chance; + return; + } + if (chance >= 0) { - if (PainChances == NULL) - { - PainChances = new PainChanceList; - } - PainChances->Insert(type, MIN(chance, 256)); - } - else if (PainChances != NULL) - { - PainChances->Remove(type); + PainChances.Push({ type, MIN(chance, 256) }); } } @@ -642,13 +619,22 @@ void PClassActor::SetPainChance(FName type, int chance) int DmgFactors::Apply(FName type, int damage) { - auto pdf = CheckKey(type); - if (pdf == NULL && type != NAME_None) + double factor = -1.; + for (auto & p : *this) { - pdf = CheckKey(NAME_None); + if (p.first == type) + { + factor = p.second; + break; + } + if (p.first == NAME_None) + { + factor = p.second; + } } - if (!pdf) return damage; - return int(damage * *pdf); + + if (factor < 0.) return damage; + return int(damage * factor); } @@ -755,13 +741,15 @@ FString DamageTypeDefinition::GetObituary(FName type) double DamageTypeDefinition::GetMobjDamageFactor(FName type, DmgFactors const * const factors) { + double defaultfac = -1.; if (factors) { // If the actor has named damage factors, look for a specific factor - - auto pdf = factors->CheckKey(type); - if (pdf) return *pdf; // type specific damage type - + for (auto & p : *factors) + { + if (p.first == type) return p.second; // type specific damage type + if (p.first == NAME_None) defaultfac = p.second; + } // If this was nonspecific damage, don't fall back to nonspecific search if (type == NAME_None) return 1.; } @@ -779,18 +767,17 @@ double DamageTypeDefinition::GetMobjDamageFactor(FName type, DmgFactors const * } { - auto pdf = factors->CheckKey(NAME_None); DamageTypeDefinition *dtd = Get(type); // Here we are looking for modifications to untyped damage // If the calling actor defines untyped damage factor, that is contained in "pdf". - if (pdf) // normal damage available + if (defaultfac >= 0.) // normal damage available { if (dtd) { if (dtd->ReplaceFactor) return dtd->DefaultFactor; // use default instead of untyped factor - return *pdf * dtd->DefaultFactor; // use default as modification of untyped factor + return defaultfac * dtd->DefaultFactor; // use default as modification of untyped factor } - return *pdf; // there was no default, so actor default is used + return defaultfac; // there was no default, so actor default is used } else if (dtd) { diff --git a/src/info.h b/src/info.h index 935d62907..406cc845b 100644 --- a/src/info.h +++ b/src/info.h @@ -201,11 +201,11 @@ struct FStateLabels #include "gametype.h" -struct DmgFactors : public TMap +struct DmgFactors : public TArray> { int Apply(FName type, int damage); }; -typedef TMap PainChanceList; +typedef TArray> PainChanceList; struct DamageTypeDefinition { @@ -244,11 +244,18 @@ struct FActorInfo PClassActor *Replacee = nullptr; FState *OwnedStates = nullptr; int NumOwnedStates = 0; + uint8_t GameFilter = GAME_Any; + uint16_t SpawnID = 0; + uint16_t ConversationID = 0; + int16_t DoomEdNum = 0; + + uint8_t DefaultStateUsage = 0; // state flag defaults for blocks without a qualifier. FActorInfo() {} FActorInfo(const FActorInfo & other) { LightAssociations = other.LightAssociations; + DefaultStateUsage = other.DefaultStateUsage; } }; @@ -293,14 +300,9 @@ public: PClassActor *GetReplacement(bool lookskill=true); PClassActor *GetReplacee(bool lookskill=true); - uint8_t GameFilter; - uint8_t DefaultStateUsage; // state flag defaults for blocks without a qualifier. - uint16_t SpawnID; - uint16_t ConversationID; - int16_t DoomEdNum; FStateLabels *StateList; - DmgFactors *DamageFactors; - PainChanceList *PainChances; + DmgFactors DamageFactors; + PainChanceList PainChances; TArray VisibleToPlayerClass; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b4db7cb0b..9368a504a 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -916,7 +916,6 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da int temp; int painchance = 0; FState * woundstate = NULL; - PainChanceList * pc = NULL; bool justhit = false; bool plrDontThrust = false; bool invulpain = false; @@ -1500,14 +1499,13 @@ fakepain: //Needed so we can skip the rest of the above, but still obey the orig if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) { - pc = target->GetClass()->PainChances; painchance = target->PainChance; - if (pc != NULL) + for (auto & pc : target->GetClass()->PainChances) { - int *ppc = pc->CheckKey(mod); - if (ppc != NULL) + if (pc.first == mod) { - painchance = *ppc; + painchance = pc.second; + break; } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0632ba20b..83233a1f0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7822,7 +7822,7 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const damage = int(damage * DamageFactor); if (damage > 0) { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, GetClass()->DamageFactors); + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, &GetClass()->DamageFactors); } return damage; } @@ -8273,10 +8273,10 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) PARAM_INT(damage); PARAM_INT(defdamage); - DmgFactors *df = itemcls->DamageFactors; - if (df != nullptr && df->CountUsed() != 0) + DmgFactors &df = itemcls->DamageFactors; + if (df.Size() != 0) { - ACTION_RETURN_INT(df->Apply(damagetype, damage)); + ACTION_RETURN_INT(df.Apply(damagetype, damage)); } else { diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 3cf2c4f7d..1984f3a97 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -124,7 +124,6 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) bag.ClassName = type->TypeName; #endif - type->GameFilter = GAME_Any; sc.MustGetStringName("{"); memset (&extra, 0, sizeof(extra)); @@ -334,7 +333,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.ScriptError ("DoomEdNum must be in the range [-1,32767]"); } - bag.Info->DoomEdNum = (int16_t)sc.Number; + bag.Info->ActorInfo()->DoomEdNum = (int16_t)sc.Number; } else if (sc.Compare ("SpawnNum")) { @@ -343,7 +342,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.ScriptError ("SpawnNum must be in the range [0,255]"); } - bag.Info->SpawnID = (uint8_t)sc.Number; + bag.Info->ActorInfo()->SpawnID = (uint8_t)sc.Number; } else if (sc.Compare ("Sprite") || ( (def == DEF_BreakableDecoration || def == DEF_Projectile) && @@ -622,7 +621,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray char *token = strtok (sc.String, ",\t\n\r"); memset (&state, 0, sizeof(state)); - state.UseFlags = info->DefaultStateUsage; + state.UseFlags = info->ActorInfo()->DefaultStateUsage; while (token != nullptr) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index edf46d3a7..8950a7067 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1016,7 +1016,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti = DecoDerivedClass(sc, parent, typeName); ti->bDecorateClass = true; // we only set this for 'modern' DECORATE. The original stuff is so limited that it cannot do anything that may require flagging. - ti->DoomEdNum = -1; + ti->ActorInfo()->DoomEdNum = -1; return ti; } @@ -1108,7 +1108,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) try { PClassActor *info = CreateNewActor(sc, typeName, parentName); - info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; + info->ActorInfo()->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); if (!info->SetReplacement(replaceName)) diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 4355941be..12684a30b 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -142,7 +142,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & char lastsprite[5] = ""; FxExpression *ScriptCode; FArgumentList *args = nullptr; - int flagdef = actor->DefaultStateUsage; + int flagdef = actor->ActorInfo()->DefaultStateUsage; FScriptPosition scp; if (sc.CheckString("(")) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 50994f1e7..aededa99f 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -391,10 +391,9 @@ bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index) case DEPF_QUARTERGRAVITY: return actor->Gravity == 1./4; case DEPF_FIRERESIST: - if (info->DamageFactors) + for (auto &df : info->DamageFactors) { - double *df = info->DamageFactors->CheckKey(NAME_Fire); - return df && (*df) == 0.5; + if (df.first == NAME_Fire) return df.second == 0.5; } return false; @@ -464,33 +463,34 @@ static bool PointerCheck(PType *symtype, PType *checktype) DEFINE_INFO_PROPERTY(game, S, Actor) { PROP_STRING_PARM(str, 0); + auto & GameFilter = info->ActorInfo()->GameFilter; if (!stricmp(str, "Doom")) { - info->GameFilter |= GAME_Doom; + GameFilter |= GAME_Doom; } else if (!stricmp(str, "Heretic")) { - info->GameFilter |= GAME_Heretic; + GameFilter |= GAME_Heretic; } else if (!stricmp(str, "Hexen")) { - info->GameFilter |= GAME_Hexen; + GameFilter |= GAME_Hexen; } else if (!stricmp(str, "Raven")) { - info->GameFilter |= GAME_Raven; + GameFilter |= GAME_Raven; } else if (!stricmp(str, "Strife")) { - info->GameFilter |= GAME_Strife; + GameFilter |= GAME_Strife; } else if (!stricmp(str, "Chex")) { - info->GameFilter |= GAME_Chex; + GameFilter |= GAME_Chex; } else if (!stricmp(str, "Any")) { - info->GameFilter = GAME_Any; + GameFilter = GAME_Any; } else { @@ -508,7 +508,7 @@ DEFINE_INFO_PROPERTY(spawnid, I, Actor) { I_Error ("SpawnID must be in the range [0,65535]"); } - else info->SpawnID=(uint16_t)id; + else info->ActorInfo()->SpawnID=(uint16_t)id; } //========================================================================== @@ -521,7 +521,7 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) PROP_INT_PARM(id2, 2); if (convid <= 0 || convid > 65535) return; // 0 is not usable because the dialogue scripts use it as 'no object'. - else info->ConversationID=(uint16_t)convid; + else info->ActorInfo()->ConversationID=(uint16_t)convid; } //========================================================================== @@ -559,7 +559,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) DEFINE_PROPERTY(defaultstateusage, I, Actor) { PROP_INT_PARM(use, 0); - static_cast(bag.Info)->DefaultStateUsage = use; + static_cast(bag.Info)->ActorInfo()->DefaultStateUsage = use; } //========================================================================== @@ -740,7 +740,7 @@ DEFINE_PROPERTY(translation, L, Actor) if (type == 0) { PROP_INT_PARM(trans, 1); - int max = 6;// (gameinfo.gametype == GAME_Strife || (info->GameFilter&GAME_Strife)) ? 6 : 2; + int max = 6; if (trans < 0 || trans > max) { I_Error ("Translation must be in the range [0,%d]", max); @@ -1133,7 +1133,7 @@ static void SetIcon(FTextureID &icon, Baggage &bag, const char *i) { // Don't print warnings if the item is for another game or if this is a shareware IWAD. // Strife's teaser doesn't contain all the icon graphics of the full game. - if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && + if ((bag.Info->ActorInfo()->GameFilter == GAME_Any || bag.Info->ActorInfo()->GameFilter & gameinfo.gametype) && !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { bag.ScriptPosition.Message(MSG_WARNING, diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 454cab470..e3e72b03c 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2889,7 +2889,7 @@ void ZCCCompiler::CompileStates() } else { - flags = static_cast(c->Type())->DefaultStateUsage; + flags = static_cast(c->Type())->ActorInfo()->DefaultStateUsage; } auto st = s->Body; if (st != nullptr) do From e4d2380775c96fb65927956a10715395f922a119 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 00:07:41 +0200 Subject: [PATCH 05/24] - moved all remaining fields from PClassActor to FActorInfo. - added a few access functions for FActorInfo variables. With PClassActor now empty the class descriptors can finally be converted back to static data outside the class hierarchy, like they were before the scripting merge, and untangle the game data from VM internals. --- src/d_dehacked.cpp | 4 +- src/d_netinfo.cpp | 8 +-- src/dobject.cpp | 2 +- src/g_skill.cpp | 2 +- src/g_statusbar/sbarinfo_commands.cpp | 2 +- src/gl/scene/gl_bsp.cpp | 4 +- src/gl/textures/gl_texture.cpp | 4 +- src/info.cpp | 41 ++------------ src/info.h | 69 ++++++++++++++++++----- src/p_interaction.cpp | 2 +- src/p_mobj.cpp | 18 +++--- src/p_saveg.cpp | 2 +- src/p_states.cpp | 25 ++++---- src/p_user.cpp | 8 +-- src/polyrenderer/scene/poly_sprite.cpp | 2 +- src/scripting/backend/codegen.cpp | 10 ++-- src/scripting/backend/codegen.h | 2 +- src/scripting/decorate/olddecorations.cpp | 3 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef.cpp | 6 +- src/scripting/thingdef_properties.cpp | 10 ++-- src/scripting/zscript/zcc_compile.cpp | 2 +- src/serializer.cpp | 6 +- src/swrenderer/r_swrenderer.cpp | 4 +- src/swrenderer/scene/r_opaque_pass.cpp | 2 +- 25 files changed, 122 insertions(+), 118 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index da68bafe4..0a360648b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1984,7 +1984,7 @@ static int PatchMisc (int dummy) player->health = deh.StartHealth; // Hm... I'm not sure that this is the right way to change this info... - FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->DropItems; + FDropItem *di = PClass::FindActor(NAME_DoomPlayer)->ActorInfo()->DropItems; while (di != NULL) { if (di->Name == NAME_Clip) @@ -3045,7 +3045,7 @@ void FinishDehPatch () if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) { // If this is a hacked non-inventory item we must also copy AInventory's special states - statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->StateList); + statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->GetStateLabels()); } statedef.InstallStates(subclass, defaults2); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 70413496c..74258e3ae 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -158,7 +158,7 @@ int D_PlayerClassToInt (const char *classname) { auto type = PlayerClasses[i].Type; - if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) + if (type->GetDisplayName().IsNotEmpty() && stricmp(type->GetDisplayName(), classname) == 0) { return i; } @@ -737,7 +737,7 @@ void D_WriteUserInfoStrings (int pnum, uint8_t **stream, bool compact) case NAME_PlayerClass: *stream += sprintf(*((char **)stream), "\\%s", info->GetPlayerClassNum() == -1 ? "Random" : - D_EscapeUserInfo(info->GetPlayerClassType()->DisplayName.GetChars()).GetChars()); + D_EscapeUserInfo(info->GetPlayerClassType()->GetDisplayName().GetChars()).GetChars()); break; case NAME_Skin: @@ -915,7 +915,7 @@ void WriteUserInfo(FSerializer &arc, userinfo_t &info) case NAME_PlayerClass: i = info.GetPlayerClassNum(); - string = (i == -1 ? "Random" : PlayerClasses[i].Type->DisplayName.GetChars()); + string = (i == -1 ? "Random" : PlayerClasses[i].Type->GetDisplayName().GetChars()); break; default: @@ -1001,7 +1001,7 @@ CCMD (playerinfo) Printf("%20s: %s (%d)\n", "Skin", Skins[ui->GetSkin()].Name.GetChars(), ui->GetSkin()); Printf("%20s: %s (%d)\n", "Gender", GenderNames[ui->GetGender()], ui->GetGender()); Printf("%20s: %s (%d)\n", "PlayerClass", - ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->DisplayName.GetChars(), + ui->GetPlayerClassNum() == -1 ? "Random" : ui->GetPlayerClassType()->GetDisplayName().GetChars(), ui->GetPlayerClassNum()); // Print generic info diff --git a/src/dobject.cpp b/src/dobject.cpp index 85e5697f6..f581091bd 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -102,7 +102,7 @@ CCMD (dumpactors) Printf("%s\t%i\t%i\t%s\t%s\n", acls->TypeName.GetChars(), ainfo->DoomEdNum, ainfo->SpawnID, filters[ainfo->GameFilter & 31], - acls->SourceLumpName.GetChars()); + acls->ActorInfo()->SourceLumpName.GetChars()); } else if (cls != NULL) { diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 04ac2f290..befd1115b 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -476,7 +476,7 @@ const char * G_SkillName() const char *name = AllSkills[gameskill].MenuName; player_t *player = &players[consoleplayer]; - const char *playerclass = player->mo->GetClass()->DisplayName; + const char *playerclass = player->mo->GetInfo()->DisplayName; if (playerclass != NULL) { diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index 458208b96..cffe67b11 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -2925,7 +2925,7 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl bool foundClass = false; for(unsigned int c = 0;c < PlayerClasses.Size();c++) { - if(stricmp(sc.String, PlayerClasses[c].Type->DisplayName) == 0) + if(stricmp(sc.String, PlayerClasses[c].Type->GetDisplayName()) == 0) { foundClass = true; classes.Push(PlayerClasses[c].Type); diff --git a/src/gl/scene/gl_bsp.cpp b/src/gl/scene/gl_bsp.cpp index 804311bc6..5222e46f3 100644 --- a/src/gl/scene/gl_bsp.cpp +++ b/src/gl/scene/gl_bsp.cpp @@ -360,7 +360,7 @@ void GLSceneDrawer::RenderThings(subsector_t * sub, sector_t * sector) if (thing->validcount == validcount) continue; thing->validcount = validcount; - FIntCVar *cvar = thing->GetClass()->distancecheck; + FIntCVar *cvar = thing->GetInfo()->distancecheck; if (cvar != NULL && *cvar >= 0) { double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared(); @@ -378,7 +378,7 @@ void GLSceneDrawer::RenderThings(subsector_t * sub, sector_t * sector) for (msecnode_t *node = sec->sectorportal_thinglist; node; node = node->m_snext) { AActor *thing = node->m_thing; - FIntCVar *cvar = thing->GetClass()->distancecheck; + FIntCVar *cvar = thing->GetInfo()->distancecheck; if (cvar != NULL && *cvar >= 0) { double dist = (thing->Pos() - r_viewpoint.Pos).LengthSquared(); diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index a7260879b..978dd1696 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -841,9 +841,9 @@ void gl_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl PClassActor *cls = pair->Key; int gltrans = GLTranslationPalette::GetInternalTranslation(GetDefaultByType(cls)->Translation); - for (int i = 0; i < cls->ActorInfo()->NumOwnedStates; i++) + for (int i = 0; i < cls->GetStateCount(); i++) { - auto &state = cls->ActorInfo()->OwnedStates[i]; + auto &state = cls->GetStates()[i]; spritelist[state.sprite].Insert(gltrans, true); FSpriteModelFrame * smf = gl_FindModelFrame(cls, state.sprite, state.Frame, false); if (smf != NULL) diff --git a/src/info.cpp b/src/info.cpp index 203a60d7a..ead6fa2d0 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -294,10 +294,6 @@ void PClassActor::StaticSetActorNums() PClassActor::PClassActor() { - StateList = NULL; - - DropItems = NULL; - // Record this in the master list. AllActorClasses.Push(this); } @@ -309,11 +305,6 @@ PClassActor::PClassActor() PClassActor::~PClassActor() { - if (StateList != NULL) - { - StateList->Destroy(); - M_Free(StateList); - } } //========================================================================== @@ -326,16 +317,6 @@ void PClassActor::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); PClassActor *newa = static_cast(newclass); - - newa->distancecheck = distancecheck; - - newa->DropItems = DropItems; - - newa->VisibleToPlayerClass = VisibleToPlayerClass; - - newa->DamageFactors = DamageFactors; - newa->PainChances = PainChances; - newa->DisplayName = DisplayName; } //========================================================================== @@ -367,20 +348,6 @@ bool PClassActor::SetReplacement(FName replaceName) return true; } -//========================================================================== -// -// PClassActor :: SetDropItems -// -// Sets a new drop item list -// -//========================================================================== - -void PClassActor::SetDropItems(FDropItem *drops) -{ - DropItems = drops; -} - - //========================================================================== // // PClassActor :: Finalize @@ -580,12 +547,12 @@ DEFINE_ACTION_FUNCTION(AActor, GetReplacee) void PClassActor::SetDamageFactor(FName type, double factor) { - for (auto & p : DamageFactors) + for (auto & p : ActorInfo()->DamageFactors) { if (p.first == type) p.second = factor; return; } - DamageFactors.Push({ type, factor }); + ActorInfo()->DamageFactors.Push({ type, factor }); } //========================================================================== @@ -596,7 +563,7 @@ void PClassActor::SetDamageFactor(FName type, double factor) void PClassActor::SetPainChance(FName type, int chance) { - for (auto & p : PainChances) + for (auto & p : ActorInfo()->PainChances) { if (p.first == type) p.second = chance; return; @@ -604,7 +571,7 @@ void PClassActor::SetPainChance(FName type, int chance) if (chance >= 0) { - PainChances.Push({ type, MIN(chance, 256) }); + ActorInfo()->PainChances.Push({ type, MIN(chance, 256) }); } } diff --git a/src/info.h b/src/info.h index 406cc845b..dc1c26fa4 100644 --- a/src/info.h +++ b/src/info.h @@ -248,14 +248,42 @@ struct FActorInfo uint16_t SpawnID = 0; uint16_t ConversationID = 0; int16_t DoomEdNum = 0; + FString SourceLumpName; + + FStateLabels *StateList = nullptr; + DmgFactors DamageFactors; + PainChanceList PainChances; + + TArray VisibleToPlayerClass; + + FDropItem *DropItems; + FIntCVar *distancecheck; + + // This is from PClassPlayerPawn + FString DisplayName; uint8_t DefaultStateUsage = 0; // state flag defaults for blocks without a qualifier. FActorInfo() {} FActorInfo(const FActorInfo & other) { - LightAssociations = other.LightAssociations; + // only copy the fields that get inherited DefaultStateUsage = other.DefaultStateUsage; + DamageFactors = other.DamageFactors; + PainChances = other.PainChances; + VisibleToPlayerClass = other.VisibleToPlayerClass; + DropItems = other.DropItems; + distancecheck = other.distancecheck; + DisplayName = other.DisplayName; + } + + ~FActorInfo() + { + if (StateList != NULL) + { + StateList->Destroy(); + M_Free(StateList); + } } }; @@ -277,13 +305,37 @@ public: void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); bool SetReplacement(FName replaceName); - void SetDropItems(FDropItem *drops); FActorInfo *ActorInfo() const { return (FActorInfo*)Meta; } + void SetDropItems(FDropItem *drops) + { + ActorInfo()->DropItems = drops; + } + + const FString &GetDisplayName() const + { + return ActorInfo()->DisplayName; + } + + FState *GetStates() const + { + return ActorInfo()->OwnedStates; + } + + unsigned GetStateCount() const + { + return ActorInfo()->NumOwnedStates; + } + + FStateLabels *GetStateLabels() const + { + return ActorInfo()->StateList; + } + FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); FState *FindState(FName name) const @@ -300,19 +352,6 @@ public: PClassActor *GetReplacement(bool lookskill=true); PClassActor *GetReplacee(bool lookskill=true); - FStateLabels *StateList; - DmgFactors DamageFactors; - PainChanceList PainChances; - - TArray VisibleToPlayerClass; - - FDropItem *DropItems; - FString SourceLumpName; - FIntCVar *distancecheck; - - // This is from PClassPlayerPawn - FString DisplayName; - // For those times when being able to scan every kind of actor is convenient static TArray AllActorClasses; }; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 9368a504a..b6bf36a08 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1500,7 +1500,7 @@ fakepain: //Needed so we can skip the rest of the above, but still obey the orig (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) { painchance = target->PainChance; - for (auto & pc : target->GetClass()->PainChances) + for (auto & pc : target->GetInfo()->PainChances) { if (pc.first == mod) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 83233a1f0..70c714650 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1607,20 +1607,16 @@ bool AActor::IsVisibleToPlayer() const const player_t* pPlayer = players[consoleplayer].camera->player; - if (pPlayer && pPlayer->mo && GetClass()->VisibleToPlayerClass.Size() > 0) + if (pPlayer) { - bool visible = false; - for(unsigned int i = 0;i < GetClass()->VisibleToPlayerClass.Size();++i) + for(auto cls : GetInfo()->VisibleToPlayerClass) { - auto cls = GetClass()->VisibleToPlayerClass[i]; if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { - visible = true; - break; + return true; } } - if (!visible) - return false; + return false; } // [BB] Passed all checks. @@ -7685,7 +7681,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) FDropItem *AActor::GetDropItems() const { - return GetClass()->DropItems; + return GetInfo()->DropItems; } DEFINE_ACTION_FUNCTION(AActor, GetDropItems) @@ -7822,7 +7818,7 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const damage = int(damage * DamageFactor); if (damage > 0) { - damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, &GetClass()->DamageFactors); + damage = DamageTypeDefinition::ApplyMobjDamageFactor(damage, damagetype, &GetInfo()->DamageFactors); } return damage; } @@ -8273,7 +8269,7 @@ DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactors) PARAM_INT(damage); PARAM_INT(defdamage); - DmgFactors &df = itemcls->DamageFactors; + DmgFactors &df = itemcls->ActorInfo()->DamageFactors; if (df.Size() != 0) { ACTION_RETURN_INT(df.Apply(damagetype, damage)); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index f191afe5d..b20e9af09 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -852,7 +852,7 @@ void CopyPlayer(player_t *dst, player_t *src, const char *name) { dst->userinfo.TransferFrom(uibackup); // The player class must come from the save, so that the menu reflects the currently playing one. - dst->userinfo.PlayerClassChanged(src->mo->GetClass()->DisplayName); + dst->userinfo.PlayerClassChanged(src->mo->GetInfo()->DisplayName); } // Validate the skin diff --git a/src/p_states.cpp b/src/p_states.cpp index b6593613a..8d10cc7a9 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -133,7 +133,7 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf FString FState::StaticGetStateName(const FState *state) { auto so = FState::StaticFindStateOwner(state); - return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->ActorInfo()->OwnedStates)); + return FStringf("%s.%d", so->TypeName.GetChars(), int(state - so->GetStates())); } //========================================================================== @@ -172,9 +172,9 @@ bool AActor::HasSpecialDeathStates () const { const PClassActor *info = static_cast(GetClass()); - if (info->StateList != NULL) + if (info->GetStateLabels() != NULL) { - FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); + FStateLabel *slabel = info->GetStateLabels()->FindLabel (NAME_Death); if (slabel != NULL && slabel->Children != NULL) { for(int i = 0; i < slabel->Children->NumLabels; i++) @@ -257,7 +257,7 @@ TArray &MakeStateNameList(const char * fname) //=========================================================================== FState *PClassActor::FindState(int numnames, FName *names, bool exact) const { - FStateLabels *labels = StateList; + FStateLabels *labels = GetStateLabels(); FState *best = NULL; if (labels != NULL) @@ -581,12 +581,13 @@ void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults) SetStateLabel("Spawn", GetDefault()->SpawnState); } - if (info->StateList != NULL) + auto &sl = info->ActorInfo()->StateList; + if (sl != NULL) { - info->StateList->Destroy(); - M_Free(info->StateList); + sl->Destroy(); + M_Free(sl); } - info->StateList = CreateStateLabelList(StateLabels); + sl = CreateStateLabelList(StateLabels); // Cache these states as member veriables. defaults->SpawnState = info->FindState(NAME_Spawn); @@ -631,9 +632,9 @@ void FStateDefinitions::MakeStateDefines(const PClassActor *cls) laststatebeforelabel = NULL; lastlabel = -1; - if (cls != NULL && cls->StateList != NULL) + if (cls != NULL && cls->GetStateLabels() != NULL) { - MakeStateList(cls->StateList, StateLabels); + MakeStateList(cls->GetStateLabels(), StateLabels); } else { @@ -816,7 +817,7 @@ void FStateDefinitions::FixStatePointers (PClassActor *actor, TArrayActorInfo()->OwnedStates + v - 1; + list[i].State = actor->GetStates() + v - 1; list[i].DefineFlags = SDF_STATE; } if (list[i].Children.Size() > 0) @@ -1095,7 +1096,7 @@ CCMD(dumpstates) { PClassActor *info = PClassActor::AllActorClasses[i]; Printf(PRINT_LOG, "State labels for %s\n", info->TypeName.GetChars()); - DumpStateHelper(info->StateList, ""); + DumpStateHelper(info->GetStateLabels(), ""); Printf(PRINT_LOG, "----------------------------\n"); } } diff --git a/src/p_user.cpp b/src/p_user.cpp index 932c5fd72..2a4f000e8 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -170,14 +170,14 @@ FString GetPrintableDisplayName(PClassActor *cls) { // Fixme; This needs a decent way to access the string table without creating a mess. // [RH] ???? - return cls->DisplayName; + return cls->GetDisplayName(); } DEFINE_ACTION_FUNCTION(APlayerPawn, GetPrintableDisplayName) { PARAM_PROLOGUE; PARAM_CLASS(type, AActor); - ACTION_RETURN_STRING(type->DisplayName); + ACTION_RETURN_STRING(type->GetDisplayName()); } bool ValidatePlayerClass(PClassActor *ti, const char *name) @@ -192,7 +192,7 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) Printf("Invalid player class '%s'\n", name); return false; } - else if (ti->DisplayName.IsEmpty()) + else if (ti->GetDisplayName().IsEmpty()) { Printf ("Missing displayname for player class '%s'\n", name); return false; @@ -267,7 +267,7 @@ CCMD (playerclasses) { Printf ("%3d: Class = %s, Name = %s\n", i, PlayerClasses[i].Type->TypeName.GetChars(), - PlayerClasses[i].Type->DisplayName.GetChars()); + PlayerClasses[i].Type->GetDisplayName().GetChars()); } } diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index ae7295f1e..2ddf46df3 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -154,7 +154,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane bool RenderPolySprite::IsThingCulled(AActor *thing) { - FIntCVar *cvar = thing->GetClass()->distancecheck; + FIntCVar *cvar = thing->GetInfo()->distancecheck; if (cvar != nullptr && *cvar >= 0) { double dist = (thing->Pos() - PolyRenderer::Instance()->Viewpoint.Pos).LengthSquared(); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 6b38999d3..7f2db4d77 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -10838,16 +10838,16 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) auto aclass = dyn_cast(ctx.Class); // This expression type can only be used from actors, for everything else it has already produced a compile error. - assert(aclass != nullptr && aclass->ActorInfo()->NumOwnedStates > 0); + assert(aclass != nullptr && aclass->GetStateCount() > 0); - if (aclass->ActorInfo()->NumOwnedStates <= index) + if (aclass->GetStateCount() <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.Class->TypeName.GetChars(), index); delete this; return nullptr; } - int symlabel = StateLabels.AddPointer(aclass->ActorInfo()->OwnedStates + index); + int symlabel = StateLabels.AddPointer(aclass->GetStates() + index); FxExpression *x = new FxConstant(symlabel, ScriptPosition); x->ValueType = TypeStateLabel; delete this; @@ -10912,8 +10912,8 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Index, ctx); } auto aclass = dyn_cast(ctx.Class); - assert(aclass != nullptr && aclass->ActorInfo()->NumOwnedStates > 0); - symlabel = StateLabels.AddPointer(aclass->ActorInfo()->OwnedStates + ctx.StateIndex); + assert(aclass != nullptr && aclass->GetStateCount() > 0); + symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); ValueType = TypeStateLabel; return this; } diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index f90a03a53..0a6b6cc44 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -2004,7 +2004,7 @@ public: class FxStateByIndex : public FxExpression { - int index; + unsigned index; public: diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 1984f3a97..7dc12d017 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -156,7 +156,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) } FState *states; - states = type->ActorInfo()->OwnedStates = (FState*)ClassDataAllocator.Alloc(StateArray.Size() * sizeof(FState)); + states = (FState*)ClassDataAllocator.Alloc(StateArray.Size() * sizeof(FState)); SaveStateSourceLines(states, SourceLines); memcpy (states, &StateArray[0], StateArray.Size() * sizeof(states[0])); if (StateArray.Size() == 1) @@ -306,6 +306,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns) } bag.statedef.SetStateLabel("Spawn", &states[extra.SpawnStart]); bag.statedef.InstallStates (type, ((AActor *)(type->Defaults))); + bag.Info->ActorInfo()->OwnedStates = states; bag.Info->ActorInfo()->NumOwnedStates = StateArray.Size(); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 8950a7067..d13c869d1 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1109,7 +1109,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) { PClassActor *info = CreateNewActor(sc, typeName, parentName); info->ActorInfo()->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; - info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); + info->ActorInfo()->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); if (!info->SetReplacement(replaceName)) { diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 0b7e35aba..0fbac19b9 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -323,7 +323,7 @@ static void CheckLabel(PClassActor *obj, FStateLabel *slb, int useflag, FName st static void CheckStateLabels(PClassActor *obj, ENamedName *test, int useflag, const char *descript) { - FStateLabels *labels = obj->StateList; + FStateLabels *labels = obj->GetStateLabels(); for (; *test != NAME_None; test++) { @@ -353,9 +353,9 @@ static void CheckStates(PClassActor *obj) { CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); } - for (int i = 0; i < obj->ActorInfo()->NumOwnedStates; i++) + for (unsigned i = 0; i < obj->GetStateCount(); i++) { - auto state = obj->ActorInfo()->OwnedStates + i; + auto state = obj->GetStates() + i; if (state->NextState && (state->UseFlags & state->NextState->UseFlags) != state->UseFlags) { GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "State %s links to a state with incompatible restrictions.\n", diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index aededa99f..fcfcb9b6b 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -391,7 +391,7 @@ bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index) case DEPF_QUARTERGRAVITY: return actor->Gravity == 1./4; case DEPF_FIRERESIST: - for (auto &df : info->DamageFactors) + for (auto &df : info->ActorInfo()->DamageFactors) { if (df.first == NAME_Fire) return df.second == 0.5; } @@ -1048,12 +1048,12 @@ DEFINE_PROPERTY(visibletoteam, I, Actor) //========================================================================== DEFINE_PROPERTY(visibletoplayerclass, Ssssssssssssssssssss, Actor) { - info->VisibleToPlayerClass.Clear(); + info->ActorInfo()->VisibleToPlayerClass.Clear(); for(int i = 0;i < PROP_PARM_COUNT;++i) { PROP_STRING_PARM(n, i); if (*n != 0) - info->VisibleToPlayerClass.Push(FindClassTentative(n, RUNTIME_CLASS(APlayerPawn))); + info->ActorInfo()->VisibleToPlayerClass.Push(FindClassTentative(n, RUNTIME_CLASS(APlayerPawn))); } } @@ -1071,7 +1071,7 @@ DEFINE_PROPERTY(distancecheck, S, Actor) } else if (cv->GetRealType() == CVAR_Int) { - static_cast(info)->distancecheck = static_cast(cv); + static_cast(info)->ActorInfo()->distancecheck = static_cast(cv); } else { @@ -1367,7 +1367,7 @@ DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - info->DisplayName = str; + info->ActorInfo()->DisplayName = str; } //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e3e72b03c..94c54dc43 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -626,7 +626,7 @@ void ZCCCompiler::CreateClassTypes() } c->cls->Type = me; auto ac = dyn_cast(me); - if (ac != nullptr) ac->SourceLumpName = *c->cls->SourceName; + if (ac != nullptr) ac->ActorInfo()->SourceLumpName = *c->cls->SourceName; } else { diff --git a/src/serializer.cpp b/src/serializer.cpp index d5b3e286b..c41fec1f3 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -1877,7 +1877,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState { arc.w->StartArray(); arc.w->String(info->TypeName.GetChars()); - arc.w->Uint((uint32_t)(state - info->ActorInfo()->OwnedStates)); + arc.w->Uint((uint32_t)(state - info->GetStates())); arc.w->EndArray(); } else @@ -1908,9 +1908,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState if (cls.IsString() && ndx.IsUint()) { PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); - if (clas && ndx.GetUint() < (unsigned)clas->ActorInfo()->NumOwnedStates) + if (clas && ndx.GetUint() < (unsigned)clas->GetStateCount()) { - state = clas->ActorInfo()->OwnedStates + ndx.GetUint(); + state = clas->GetStates() + ndx.GetUint(); } else { diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index 11f4d801b..9f6da2a14 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -132,9 +132,9 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & { PClassActor *cls = pair->Key; - for (int i = 0; i < cls->ActorInfo()->NumOwnedStates; i++) + for (unsigned i = 0; i < cls->GetStateCount(); i++) { - spritelist[cls->ActorInfo()->OwnedStates[i].sprite] = true; + spritelist[cls->GetStates()[i].sprite] = true; } } diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 23876235f..12bb95513 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -844,7 +844,7 @@ namespace swrenderer //if (thing->validcount == validcount) continue; //thing->validcount = validcount; - FIntCVar *cvar = thing->GetClass()->distancecheck; + FIntCVar *cvar = thing->GetInfo()->distancecheck; if (cvar != nullptr && *cvar >= 0) { double dist = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared(); From 0e0eca0e0f1ae4306a4a8c56645222f6ca25d0e7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 01:29:51 +0200 Subject: [PATCH 06/24] - replaced some dyn_casts with calls to FindActor. - fixed type checks in A_Morph. --- src/g_inventory/a_weapons.cpp | 8 ++++---- src/g_shared/a_morph.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index c325a55ca..9d7f184d0 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1269,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(PClass::FindActor(argv[i])); } } } @@ -1298,7 +1298,7 @@ CCMD (addslot) return; } - PClassActor *type= dyn_cast(PClass::FindClass(argv[2])); + PClassActor *type= PClass::FindActor(argv[2]); if (type == nullptr) { Printf("%s is not a weapon\n", argv[2]); @@ -1374,7 +1374,7 @@ CCMD (addslotdefault) return; } - type = dyn_cast(PClass::FindClass(argv[2])); + type = PClass::FindActor(argv[2]); if (type == nullptr) { Printf ("%s is not a weapon\n", argv[2]); @@ -1523,7 +1523,7 @@ void P_ReadDemoWeaponsChunk(uint8_t **demo) for (i = 1; i < count; ++i) { s = ReadStringConst(demo); - type = dyn_cast(PClass::FindClass(s)); + type = PClass::FindActor(s); // If a demo was recorded with a weapon that is no longer present, // should we report it? Weapons_ntoh[i] = type; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 36ffd800b..f7177165e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -714,14 +714,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_Morph) bool res = false; if (self->player) { - if (type->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + if (type->IsDescendantOf(RUNTIME_CLASS(APlayerPawn))) { res = P_MorphPlayer(self->player, self->player, type, duration, flags, enter_flash, exit_flash); } } else { - if (type->IsKindOf(RUNTIME_CLASS(AMorphedMonster))) + if (type->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster))) { res = P_MorphMonster(self, type, duration, flags, enter_flash, exit_flash); } From 5350721ec512139f30840cd5f6f7f759f3c6d775 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 09:55:27 +0200 Subject: [PATCH 07/24] - removed PClass::DeriveData because it is no longer needed. - fixed: IsVisibleToPlayer and optimized it a bit more. - moved SourceLumpName to PClass, so that it can also be used for non-actors (there's a lot of non-Actor classes already.) - separated the serializer for PClassPointer from PPointer. Even though not doable, a pointer to a class type is something entirely different than a class pointer with a restriction so each should handle its own case. --- src/dobject.cpp | 6 +-- src/dobjtype.cpp | 64 ++++++++++------------- src/dobjtype.h | 4 +- src/info.cpp | 12 ----- src/info.h | 4 +- src/p_mobj.cpp | 5 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 5 +- 8 files changed, 40 insertions(+), 62 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index f581091bd..95dc5980e 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -91,7 +91,7 @@ CCMD (dumpactors) "25:DoomStrifeChex", "26:HereticStrifeChex", "27:NotHexen", "28:HexenStrifeChex", "29:NotHeretic", "30:NotDoom", "31:All", }; - Printf("%i object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::AllClasses.Size()); + Printf("%u object class types total\nActor\tEd Num\tSpawnID\tFilter\tSource\n", PClass::AllClasses.Size()); for (unsigned int i = 0; i < PClass::AllClasses.Size(); i++) { PClass *cls = PClass::AllClasses[i]; @@ -102,11 +102,11 @@ CCMD (dumpactors) Printf("%s\t%i\t%i\t%s\t%s\n", acls->TypeName.GetChars(), ainfo->DoomEdNum, ainfo->SpawnID, filters[ainfo->GameFilter & 31], - acls->ActorInfo()->SourceLumpName.GetChars()); + acls->SourceLumpName.GetChars()); } else if (cls != NULL) { - Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\n", cls->TypeName.GetChars()); + Printf("%s\tn/a\tn/a\tn/a\tEngine (not an actor type)\tSource: %s\n", cls->TypeName.GetChars(), cls->SourceLumpName.GetChars()); } else { diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c3932e068..9f8b88deb 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1421,16 +1421,7 @@ void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) con { if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - auto pt = static_cast(PointedType); - - if (pt->IsDescendantOf(RUNTIME_CLASS(PClass))) - { - ar(key, *(PClass **)addr); - } - else - { - ar(key, *(DObject **)addr); - } + ar(key, *(DObject **)addr); } else if (writer != nullptr) { @@ -1452,17 +1443,8 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const { if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) { - 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); - } + bool res; + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); return res; } else if (reader != nullptr) @@ -1550,13 +1532,34 @@ 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; + loadOp = OP_LP; storeOp = OP_SP; mVersion = restrict->mVersion; } +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PClassPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(PClass **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PClassPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + return false; +} + //========================================================================== // // PClassPointer - isCompatible @@ -3304,18 +3307,6 @@ void PClass::InitializeDefaults() } } -//========================================================================== -// -// PClass :: DeriveData -// -// Copies inheritable data to the child class. -// -//========================================================================== - -void PClass::DeriveData(PClass *newclass) -{ -} - //========================================================================== // // PClass :: CreateDerivedClass @@ -3365,7 +3356,6 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { type->InitializeDefaults(); type->Virtuals = Virtuals; - DeriveData(type); } else type->ObjectFlags &= OF_Transient; diff --git a/src/dobjtype.h b/src/dobjtype.h index de364c4f8..7e485f194 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -429,6 +429,8 @@ public: class PClass *ClassRestriction; bool isCompatible(PType *type); + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; @@ -600,7 +602,6 @@ public: bool ReadAllFields(FSerializer &ar, void *addr) const; void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); - virtual void DeriveData(PClass *newclass); static void StaticInit(); static void StaticShutdown(); @@ -619,6 +620,7 @@ public: bool bExported; // This type has been declared in a script bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility TArray Virtuals; // virtual function table + FName SourceLumpName; void (*ConstructNative)(void *); diff --git a/src/info.cpp b/src/info.cpp index ead6fa2d0..6f00609af 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -307,18 +307,6 @@ PClassActor::~PClassActor() { } -//========================================================================== -// -// PClassActor :: Derive -// -//========================================================================== - -void PClassActor::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); - PClassActor *newa = static_cast(newclass); -} - //========================================================================== // // PClassActor :: SetReplacement diff --git a/src/info.h b/src/info.h index dc1c26fa4..6be614aa7 100644 --- a/src/info.h +++ b/src/info.h @@ -247,8 +247,7 @@ struct FActorInfo uint8_t GameFilter = GAME_Any; uint16_t SpawnID = 0; uint16_t ConversationID = 0; - int16_t DoomEdNum = 0; - FString SourceLumpName; + int16_t DoomEdNum = -1; FStateLabels *StateList = nullptr; DmgFactors DamageFactors; @@ -294,7 +293,6 @@ protected: public: static void StaticInit (); static void StaticSetActorNums (); - virtual void DeriveData(PClass *newclass); PClassActor(); ~PClassActor(); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 70c714650..30e462b10 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1605,11 +1605,14 @@ bool AActor::IsVisibleToPlayer() const (signed)(VisibleToTeam-1) != players[consoleplayer].userinfo.GetTeam() ) return false; + auto &vis = GetInfo()->VisibleToPlayerClass; + if (vis.Size() == 0) return true; // early out for the most common case. + const player_t* pPlayer = players[consoleplayer].camera->player; if (pPlayer) { - for(auto cls : GetInfo()->VisibleToPlayerClass) + for(auto cls : vis) { if (cls && pPlayer->mo->GetClass()->IsDescendantOf(cls)) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index d13c869d1..8950a7067 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1109,7 +1109,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) { PClassActor *info = CreateNewActor(sc, typeName, parentName); info->ActorInfo()->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; - info->ActorInfo()->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); + info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); if (!info->SetReplacement(replaceName)) { diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 94c54dc43..0feda59e6 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -625,8 +625,7 @@ void ZCCCompiler::CreateClassTypes() DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); } c->cls->Type = me; - auto ac = dyn_cast(me); - if (ac != nullptr) ac->ActorInfo()->SourceLumpName = *c->cls->SourceName; + me->SourceLumpName = *c->cls->SourceName; } else { @@ -2194,7 +2193,6 @@ void ZCCCompiler::InitDefaults() FString mename = ti->TypeName.GetChars(); ti->InitializeDefaults(); - ti->ParentClass->DeriveData(ti); } } else @@ -2215,7 +2213,6 @@ void ZCCCompiler::InitDefaults() auto ti = static_cast(c->Type()); ti->InitializeDefaults(); - ti->ParentClass->DeriveData(ti); // We need special treatment for this one field in AActor's defaults which cannot be made visible to DECORATE as a property. // It's better to do this here under controlled conditions than deeper down in the class type classes. From 9c9b2ccf6d341296100b4effe52fa8a92468fed2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 10:20:58 +0200 Subject: [PATCH 08/24] - replaced more dyn_casts and checks for RUNTIME_CLASS(PClassActor) It is preferable to use IsDescendantOf wherever possible if we ever want to be able to separate PClass from PType. --- src/actor.h | 11 +++++++++++ src/d_dehacked.cpp | 2 +- src/d_net.cpp | 2 +- src/dobject.cpp | 2 +- src/dobjtype.cpp | 2 +- src/info.h | 5 ----- src/p_acs.cpp | 3 +-- src/p_conversation.cpp | 6 +++--- src/p_mobj.cpp | 4 ++-- src/p_states.cpp | 4 ++-- src/scripting/backend/codegen.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 4 ++-- src/scripting/zscript/zcc_compile.cpp | 4 ++-- 13 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/actor.h b/src/actor.h index a856103dd..7a7e55518 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1572,6 +1572,17 @@ template inline T *Spawn() // for inventory items we do not need coordi return static_cast(AActor::StaticSpawn(RUNTIME_TEMPLATE_CLASS(T), DVector3(0, 0, 0), NO_REPLACE)); } +inline PClassActor *PClass::FindActor(FName name) +{ + auto cls = FindClass(name); + return cls && cls->IsDescendantOf(RUNTIME_CLASS(AActor)) ? static_cast(cls) : nullptr; +} + +inline PClassActor *ValidateActor(PClass *cls) +{ + return cls && cls->IsDescendantOf(RUNTIME_CLASS(AActor)) ? static_cast(cls) : nullptr; +} + void PrintMiscActorInfo(AActor * query); AActor *P_LinePickActor(AActor *t1, DAngle angle, double distance, DAngle pitch, ActorFlags actorMask, uint32_t wallMask); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 0a360648b..8bb16a687 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2827,7 +2827,7 @@ static bool LoadDehSupp () { sc.ScriptError ("Can't find type %s", sc.String); } - else if (!type->IsKindOf(RUNTIME_CLASS(PClassActor))) + else if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) { sc.ScriptError ("%s is not an actor", sc.String); } diff --git a/src/d_net.cpp b/src/d_net.cpp index 0af1bd9c1..12449111a 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2592,7 +2592,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) char *classname = ReadString(stream); int removecount = 0; PClassActor *cls = PClass::FindActor(classname); - if (cls != NULL && cls->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AActor))) { removecount = RemoveClass(cls); const PClass *cls_rep = cls->GetReplacement(); diff --git a/src/dobject.cpp b/src/dobject.cpp index 95dc5980e..a28ff62fc 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -95,7 +95,7 @@ CCMD (dumpactors) for (unsigned int i = 0; i < PClass::AllClasses.Size(); i++) { PClass *cls = PClass::AllClasses[i]; - PClassActor *acls = dyn_cast(cls); + PClassActor *acls = ValidateActor(cls); if (acls != NULL) { auto ainfo = acls->ActorInfo(); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 9f8b88deb..88b6aa9e4 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -3229,7 +3229,7 @@ void PClass::Derive(PClass *newclass, FName name) void PClass::InitializeDefaults() { - if (IsKindOf(RUNTIME_CLASS(PClassActor))) + if (IsDescendantOf(RUNTIME_CLASS(AActor))) { assert(Defaults == nullptr); Defaults = (uint8_t *)M_Malloc(Size); diff --git a/src/info.h b/src/info.h index 6be614aa7..907b9a3b2 100644 --- a/src/info.h +++ b/src/info.h @@ -354,11 +354,6 @@ public: static TArray AllActorClasses; }; -inline PClassActor *PClass::FindActor(FName name) -{ - return dyn_cast(FindClass(name)); -} - struct FDoomEdEntry { PClassActor *Type; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f9e0f58e7..f198f7e10 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9777,8 +9777,7 @@ scriptwait: } else { - AInventory *item = activator->FindInventory (dyn_cast( - PClass::FindClass (FBehavior::StaticLookupString (STACK(1))))); + AInventory *item = activator->FindInventory (PClass::FindActor (FBehavior::StaticLookupString (STACK(1)))); if (item == NULL || !item->IsKindOf(NAME_Weapon)) { diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index d01fb5193..0e734479a 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -367,7 +367,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, uint32_t &prevSpea node->SpeakerName = speech.Name; // The item the speaker should drop when killed. - node->DropType = dyn_cast(GetStrifeType(speech.DropType)); + node->DropType = GetStrifeType(speech.DropType); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); @@ -447,7 +447,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, uint32_t &prevSpea node->SpeakerName = speech.Name; // The item the speaker should drop when killed. - node->DropType = dyn_cast(GetStrifeType (speech.DropType)); + node->DropType = GetStrifeType (speech.DropType); // Items you need to have to make the speaker use a different node. node->ItemCheck.Resize(3); @@ -512,7 +512,7 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->LogString = ""; // The item to receive when this reply is used. - reply->GiveType = dyn_cast(GetStrifeType (rsp->GiveType)); + reply->GiveType = GetStrifeType (rsp->GiveType); reply->ActionSpecial = 0; // Do you need anything special for this reply to succeed? diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 30e462b10..f702606ce 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5041,7 +5041,7 @@ PClassActor *ClassForSpawn(FName classname) { I_Error("Attempt to spawn actor of unknown type '%s'\n", classname.GetChars()); } - if (!cls->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!cls->IsDescendantOf(RUNTIME_CLASS(AActor))) { I_Error("Attempt to spawn non-actor of type '%s'\n", classname.GetChars()); } @@ -5863,7 +5863,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) Printf ("%s at (%.1f, %.1f) has no frames\n", i->TypeName.GetChars(), mthing->pos.X, mthing->pos.Y); i = PClass::FindActor("Unknown"); - assert(i->IsKindOf(RUNTIME_CLASS(PClassActor))); + assert(i->IsDescendantOf(RUNTIME_CLASS(AActor))); } const AActor *info = GetDefaultByType (i); diff --git a/src/p_states.cpp b/src/p_states.cpp index 8d10cc7a9..fae4e13df 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -120,7 +120,7 @@ PClassActor *FState::StaticFindStateOwner (const FState *state, PClassActor *inf { return info; } - info = dyn_cast(info->ParentClass); + info = ValidateActor(info->ParentClass); } return NULL; } @@ -739,7 +739,7 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, // superclass, or it may be the name of any class that this one derives from. if (stricmp (classname, "Super") == 0) { - type = dyn_cast(type->ParentClass); + type = ValidateActor(type->ParentClass); actor = GetDefaultByType(type); } else diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 7f2db4d77..66f9f308e 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -10982,7 +10982,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) } else if (names[0] == NAME_Super) { - scope = dyn_cast(clstype->ParentClass); + scope = ValidateActor(clstype->ParentClass); } else { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 8950a7067..adda5b0e9 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -582,7 +582,7 @@ static FState *CheckState(FScanner &sc, PClass *type) FState *state = NULL; sc.MustGetString(); - PClassActor *info = dyn_cast(type->ParentClass); + PClassActor *info = ValidateActor(type->ParentClass); if (info != NULL) { @@ -999,7 +999,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); break; } - p = dyn_cast(p->ParentClass); + p = ValidateActor(p->ParentClass); } if (parent == NULL) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 0feda59e6..572e5a422 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1385,7 +1385,7 @@ void ZCCCompiler::CompileAllProperties() bool ZCCCompiler::CompileProperties(PClass *type, TArray &Properties, FName prefix) { - if (!type->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!type->IsDescendantOf(RUNTIME_CLASS(AActor))) { Error(Properties[0], "Properties can only be defined for actors"); return false; @@ -2850,7 +2850,7 @@ void ZCCCompiler::CompileStates() 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)); + statedef.MakeStateDefines(ValidateActor(c->Type()->ParentClass)); int numframes = 0; for (auto s : c->States) From 80801d11b197dab3e7a42044a4958fbe7c07298d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 10:29:04 +0200 Subject: [PATCH 09/24] - removed some redundant static_casts. --- src/g_inventory/a_weapons.cpp | 4 ++-- src/g_shared/shared_hud.cpp | 9 ++++----- src/info.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/thingdef_properties.cpp | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 9d7f184d0..e4079121a 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -514,7 +514,7 @@ FState *AWeapon::GetStateForButtonName (FName button) bool FWeaponSlot::AddWeapon(const char *type) { - return AddWeapon(static_cast(PClass::FindClass(type))); + return AddWeapon(PClass::FindActor(type)); } bool FWeaponSlot::AddWeapon(PClassActor *type) @@ -1443,7 +1443,7 @@ void P_SetupWeapons_ntohton() if (cls->IsDescendantOf(NAME_Weapon)) { - Weapons_ntoh.Push(static_cast(cls)); + Weapons_ntoh.Push(cls); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 19183a437..c414a9275 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -385,21 +385,20 @@ static void SetKeyTypes() { for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) { - PClass *ti = PClassActor::AllActorClasses[i]; + PClassActor *ti = PClassActor::AllActorClasses[i]; auto kt = PClass::FindActor(NAME_Key); if (ti->IsDescendantOf(kt)) { - PClassActor *tia = static_cast(ti); - AInventory *key = (AInventory*)(GetDefaultByType(tia)); + AInventory *key = (AInventory*)(GetDefaultByType(ti)); if (key->Icon.isValid() && key->special1 > 0) { - KeyTypes.Push(tia); + KeyTypes.Push(ti); } else { - UnassignedKeyTypes.Push(tia); + UnassignedKeyTypes.Push(ti); } } } diff --git a/src/info.cpp b/src/info.cpp index 6f00609af..71216cc06 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -282,7 +282,7 @@ void PClassActor::StaticSetActorNums() { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { - static_cast(PClassActor::AllActorClasses[i])->RegisterIDs(); + PClassActor::AllActorClasses[i]->RegisterIDs(); } } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index adda5b0e9..7b31336fd 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -1116,7 +1116,7 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->TypeName.GetChars()); } - ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast(info->ParentClass)); + ResetBaggage (bag, ValidateActor(info->ParentClass)); bag->Info = info; bag->Lumpnum = sc.LumpNum; #ifdef _DEBUG diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index fcfcb9b6b..b2a922b46 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -1071,7 +1071,7 @@ DEFINE_PROPERTY(distancecheck, S, Actor) } else if (cv->GetRealType() == CVAR_Int) { - static_cast(info)->ActorInfo()->distancecheck = static_cast(cv); + info->ActorInfo()->distancecheck = static_cast(cv); } else { From bc486904cd45effda0bfb2ef669cd4ae6984688d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 10:52:54 +0200 Subject: [PATCH 10/24] - split PPointer into PPointer and PObjectPointer. A pointer to an object has quite different semantics so let's do this with proper virtual inheritance. This should allow to simplify a lot of pointer related checks in the compiler. --- src/dobjtype.cpp | 130 ++++++++++++++++++++++++++++++----------------- src/dobjtype.h | 13 ++++- 2 files changed, 94 insertions(+), 49 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 88b6aa9e4..abbe60dca 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1338,7 +1338,10 @@ PPointer::PPointer() : PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) { mDescriptiveName = "NullPointer"; - SetOps(); + loadOp = OP_LP; + storeOp = OP_SP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; } //========================================================================== @@ -1352,20 +1355,8 @@ PPointer::PPointer(PType *pointsat, bool isconst) { mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); mVersion = pointsat->mVersion; - SetOps(); -} - -//========================================================================== -// -// PPointer :: GetStoreOp -// -//========================================================================== - -void PPointer::SetOps() -{ - 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; + loadOp = OP_LP; + storeOp = OP_SP; moveOp = OP_MOVEA; RegType = REGT_POINTER; } @@ -1396,21 +1387,6 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } -//========================================================================== -// -// PPointer :: SetPointer -// -//========================================================================== - -void PPointer::SetPointer(void *base, unsigned offset, TArray *special) const -{ - if (PointedType != nullptr && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) - { - // Add to the list of pointers for this class. - special->Push(offset); - } -} - //========================================================================== // // PPointer :: WriteValue @@ -1419,11 +1395,7 @@ 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(PClass))) - { - ar(key, *(DObject **)addr); - } - else if (writer != nullptr) + if (writer != nullptr) { writer(ar, key, addr); } @@ -1441,19 +1413,67 @@ 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(PClass))) - { - bool res; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); - return res; - } - else if (reader != nullptr) + if (reader != nullptr) { return reader(ar, key, addr); } return false; } +/* PObjectPointer **********************************************************/ + +IMPLEMENT_CLASS(PObjectPointer, false, false) + +//========================================================================== +// +// PPointer :: GetStoreOp +// +//========================================================================== + +PObjectPointer::PObjectPointer(PClass *cls, bool isconst) + : PPointer(cls, isconst) +{ + loadOp = OP_LO; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + if (cls && !cls->IsDescendantOf(RUNTIME_CLASS(DThinker))) storeOp = OP_SO; +} + +//========================================================================== +// +// PPointer :: SetPointer +// +//========================================================================== + +void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) const +{ + // Add to the list of pointers for this class. + special->Push(offset); +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PObjectPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(DObject **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res; + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + return res; +} + //========================================================================== // // NewPointer @@ -1464,14 +1484,28 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const 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 == nullptr) + if (type->IsKindOf(RUNTIME_CLASS(PClass))) { - ptype = new PPointer(type, isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PObjectPointer(static_cast(type), isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); + } + else + { + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); } - return static_cast(ptype); } /* PStatePointer **********************************************************/ diff --git a/src/dobjtype.h b/src/dobjtype.h index 7e485f194..abee1e36d 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -400,7 +400,6 @@ public: virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; @@ -420,6 +419,18 @@ public: }; +class PObjectPointer : public PPointer +{ + DECLARE_CLASS(PObjectPointer, PPointer); +public: + PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; +}; + + class PClassPointer : public PPointer { DECLARE_CLASS(PClassPointer, PPointer); From b17ab7a1334967de278c7f83e6e5b52bb67f9e29 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 11:40:40 +0200 Subject: [PATCH 11/24] - put PObjectPointer to some use. - fixed: There was no check for compatible class pointers. --- src/dobjtype.h | 1 + src/scripting/backend/codegen.cpp | 20 +++++++++++++++----- src/scripting/backend/codegen.h | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index abee1e36d..a4d0f4402 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -428,6 +428,7 @@ public: void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; + PClass *PointedClass() const; }; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 66f9f308e..8414762b0 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -56,6 +56,8 @@ #include "w_wad.h" #include "math/cmath.h" +inline PClass *PObjectPointer::PointedClass() const { return static_cast(PointedType); } + extern FRandom pr_exrandom; FMemArena FxAlloc(65536); int utf8_decode(const char *src, int *size); @@ -294,10 +296,18 @@ static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompar // A type is always compatible to itself. if (fromtype == totype) return true; // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. - if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + if (source->IsA(RUNTIME_CLASS(PObjectPointer)) && dest->IsA(RUNTIME_CLASS(PObjectPointer))) { - auto fromcls = static_cast(fromtype->PointedType); - auto tocls = static_cast(totype->PointedType); + auto fromcls = static_cast(source)->PointedClass(); + auto tocls = static_cast(dest)->PointedClass(); + if (forcompare && tocls->IsDescendantOf(fromcls)) return true; + return (fromcls->IsDescendantOf(tocls)); + } + // The same rules apply to class pointers. A child type can be assigned to a variable of a parent type. + if (source->IsA(RUNTIME_CLASS(PClassPointer)) && dest->IsA(RUNTIME_CLASS(PClassPointer))) + { + auto fromcls = static_cast(source)->ClassRestriction; + auto tocls = static_cast(dest)->ClassRestriction; if (forcompare && tocls->IsDescendantOf(fromcls)) return true; return (fromcls->IsDescendantOf(tocls)); } @@ -6958,8 +6968,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) if (membervar->SymbolName == NAME_Default) { - if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) - || !static_cast(classx->ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(AActor))) + if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)) + || !static_cast(classx->ValueType)->PointedClass()->IsDescendantOf(RUNTIME_CLASS(AActor))) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type"); delete this; diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 0a6b6cc44..f1a322d7a 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -333,7 +333,7 @@ public: bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } - bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } + bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PObjectPointer)); } bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } From 63082510846afba5379bc678d73aed6646399090 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 13:08:41 +0200 Subject: [PATCH 12/24] - added a FindSymbol wrapper to PClass so that other code does not need to access the symbol table directly. - added an isActor utility function to codegen.cpp to simplify a few constructs. --- src/actor.h | 1 - src/d_dehacked.cpp | 8 ++++---- src/dobject.cpp | 2 +- src/dobjtype.cpp | 11 ++++++++--- src/dobjtype.h | 1 + src/menu/menu.cpp | 12 ++++++------ src/menu/menudef.cpp | 4 ++-- src/menu/messagebox.cpp | 2 +- src/p_acs.cpp | 4 ++-- src/p_actionfunctions.cpp | 4 ++-- src/p_setup.cpp | 2 +- src/scripting/backend/codegen.cpp | 18 ++++++++++++------ src/scripting/decorate/thingdef_exp.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 2 +- src/scripting/decorate/thingdef_states.cpp | 4 ++-- src/scripting/thingdef_data.cpp | 2 +- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/zscript/zcc_compile.cpp | 4 ++-- src/virtual.h | 2 +- 19 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/actor.h b/src/actor.h index 7a7e55518..666ca67f8 100644 --- a/src/actor.h +++ b/src/actor.h @@ -33,7 +33,6 @@ // States are tied to finite states are tied to animation frames. #include "info.h" -#include #include "doomdef.h" #include "textures/textures.h" #include "r_data/renderstyle.h" diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 8bb16a687..31a5ec784 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -791,7 +791,7 @@ void SetDehParams(FState *state, int codepointer) // Let's identify the codepointer we're dealing with. PFunction *sym; - sym = dyn_cast(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); + sym = dyn_cast(RUNTIME_CLASS(AWeapon)->FindSymbol(FName(MBFCodePointers[codepointer].name), true)); if (sym == NULL) return; if (codepointer < 0 || (unsigned)codepointer >= countof(MBFCodePointerFactories)) @@ -2118,7 +2118,7 @@ static int PatchCodePtrs (int dummy) // This skips the action table and goes directly to the internal symbol table // DEH compatible functions are easy to recognize. - PFunction *sym = dyn_cast(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(symname, true)); + PFunction *sym = dyn_cast(RUNTIME_CLASS(AWeapon)->FindSymbol(symname, true)); if (sym == NULL) { Printf(TEXTCOLOR_RED "Frame %d: Unknown code pointer '%s'\n", frame, Line2); @@ -2744,7 +2744,7 @@ static bool LoadDehSupp () // or AActor so this will find all of them. FString name = "A_"; name << sc.String; - PFunction *sym = dyn_cast(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(name, true)); + PFunction *sym = dyn_cast(RUNTIME_CLASS(AWeapon)->FindSymbol(name, true)); if (sym == NULL) { sc.ScriptError("Unknown code pointer '%s'", sc.String); @@ -3116,7 +3116,7 @@ void FinishDehPatch () { if (AmmoPerAttacks[j].ptr == nullptr) { - auto p = dyn_cast(RUNTIME_CLASS(AWeapon)->Symbols.FindSymbol(AmmoPerAttacks[j].func, true)); + auto p = dyn_cast(RUNTIME_CLASS(AWeapon)->FindSymbol(AmmoPerAttacks[j].func, true)); if (p != nullptr) AmmoPerAttacks[j].ptr = p->Variants[0].Implementation; } if (state->ActionFunc == AmmoPerAttacks[j].ptr) diff --git a/src/dobject.cpp b/src/dobject.cpp index a28ff62fc..ca2a3e32f 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -625,7 +625,7 @@ DEFINE_ACTION_FUNCTION(DObject, MSTime) void *DObject::ScriptVar(FName field, PType *type) { auto cls = GetClass(); - auto sym = dyn_cast(cls->Symbols.FindSymbol(field, true)); + auto sym = dyn_cast(cls->FindSymbol(field, true)); if (sym && (sym->Type == type || type == nullptr)) { if (!(sym->Flags & VARF_Meta)) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index abbe60dca..96314d025 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2088,7 +2088,7 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const { - if (ElementType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ElementType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && static_cast(ElementType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + if (ElementType->IsKindOf(RUNTIME_CLASS(PObjectPointer))) { // Add to the list of pointer arrays for this class. special->Push(offset); @@ -3554,6 +3554,11 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) return -1; } +PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const +{ + return Symbols.FindSymbol(symname, searchparents); +} + //========================================================================== // // PClass :: BuildFlatPointers @@ -3722,7 +3727,7 @@ VMFunction *PClass::FindFunction(FName clsname, FName funcname) { auto cls = PClass::FindClass(clsname); if (!cls) return nullptr; - auto func = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + auto func = dyn_cast(cls->FindSymbol(funcname, true)); if (!func) return nullptr; return func->Variants[0].Implementation; } @@ -3731,7 +3736,7 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) { auto cls = PClass::FindClass(clsname); if (!cls) return; - auto func = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + auto func = dyn_cast(cls->FindSymbol(funcname, true)); if (!func) return; *pptr = func->Variants[0].Implementation; FunctionPtrList.Push(pptr); diff --git a/src/dobjtype.h b/src/dobjtype.h index a4d0f4402..27248e955 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -614,6 +614,7 @@ public: bool ReadAllFields(FSerializer &ar, void *addr) const; void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); + PSymbol *FindSymbol(FName symname, bool searchparents) const; static void StaticInit(); static void StaticShutdown(); diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index be14b2f09..5f7d4bfe5 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1127,7 +1127,7 @@ DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v) auto p = c->CreateNew(); FString namestr = name; VMValue params[] = { p, &namestr, v }; - auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + auto f = dyn_cast(c->FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1138,7 +1138,7 @@ DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickCo auto p = c->CreateNew(); FString namestr = label; VMValue params[] = { p, &namestr, joy }; - auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + auto f = dyn_cast(c->FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1149,7 +1149,7 @@ DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int ce auto p = c->CreateNew(); FString namestr = label; VMValue params[] = { p, &namestr, cmd.GetIndex(), center }; - auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + auto f = dyn_cast(c->FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1160,7 +1160,7 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi auto p = c->CreateNew(); FString namestr = label; VMValue params[] = { p, &namestr, cmd.GetIndex(), bindings }; - auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + auto f = dyn_cast(c->FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1171,7 +1171,7 @@ DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotk auto p = c->CreateNew(); FString keystr = FString(char(hotkey)); VMValue params[] = { p, x, y, height, tex.GetIndex(), &keystr, command.GetIndex(), param }; - auto f = dyn_cast(c->Symbols.FindSymbol("InitDirect", false)); + auto f = dyn_cast(c->FindSymbol("InitDirect", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1183,7 +1183,7 @@ DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotke FString keystr = FString(char(hotkey)); FString textstr = text; VMValue params[] = { p, x, y, height, &keystr, &textstr, font, int(color1.d), int(color2.d), command.GetIndex(), param }; - auto f = dyn_cast(c->Symbols.FindSymbol("InitDirect", false)); + auto f = dyn_cast(c->FindSymbol("InitDirect", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index ce7137293..458a89502 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -371,7 +371,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("ListMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); + auto func = dyn_cast(cls->FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; @@ -746,7 +746,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); + auto func = dyn_cast(cls->FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 514331d7f..a7a69dbb5 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -70,7 +70,7 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, FString namestr = message; VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; - auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); + auto f = dyn_cast(c->FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenu*)p; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f198f7e10..0feb013f4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5012,7 +5012,7 @@ int DLevelScript::LineFromID(int id) bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type, bool readonly) { - PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); PArray *arraytype; if (var == NULL || (!readonly && (var->Flags & VARF_Native))) @@ -5362,7 +5362,7 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) { I_Error("ACS call to unknown class in script function %s.%s", clsname, funcname); } - auto funcsym = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + auto funcsym = dyn_cast(cls->FindSymbol(funcname, true)); if (funcsym == nullptr) { I_Error("ACS call to unknown script function %s.%s", clsname, funcname); diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 5ffc88384..a23316bd1 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4749,7 +4749,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeVelocity) static PField *GetVar(DObject *self, FName varname) { - PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { @@ -4798,7 +4798,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetUserVarFloat) static PField *GetArrayVar(DObject *self, FName varname, int pos) { - PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast(self->GetClass()->FindSymbol(varname, true)); if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || diff --git a/src/p_setup.cpp b/src/p_setup.cpp index eccad199e..e91de462a 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1616,7 +1616,7 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) { FName varname = MapThingsUserData[udi].Property; int value = MapThingsUserData[udi].Value; - PField *var = dyn_cast(actor->GetClass()->Symbols.FindSymbol(varname, true)); + PField *var = dyn_cast(actor->GetClass()->FindSymbol(varname, true)); udi++; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 8414762b0..a87e249a8 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -224,6 +224,12 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) return nullptr; } +bool isActor(PStruct *type) +{ + auto cls = dyn_cast(type); + return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; +} + //========================================================================== // // ExpEmit @@ -5963,7 +5969,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) delete this; return nullptr; } - if (!ctx.Function->Variants[0].SelfClass->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!isActor(ctx.Function->Variants[0].SelfClass)) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); delete this; @@ -6123,7 +6129,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct if (Identifier == NAME_Default) { - if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!isActor(objtype)) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); delete object; @@ -7689,7 +7695,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - FxExpression *self = (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_Method) && ctx.Class->IsKindOf(RUNTIME_CLASS(PClassActor))) ? new FxSelf(ScriptPosition) : (FxExpression*)new FxConstant(ScriptPosition); + FxExpression *self = (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_Method) && isActor(ctx.Class)) ? new FxSelf(ScriptPosition) : (FxExpression*)new FxConstant(ScriptPosition); FxExpression *x = new FxActionSpecialCall(self, special, ArgList, ScriptPosition); delete this; return x->Resolve(ctx); @@ -10693,9 +10699,9 @@ int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numpar // Let the caller check this. Making this an error with a message is only taking away options from the user. cls = nullptr; } - ret->SetObject(const_cast(cls)); + ret->SetPointer(const_cast(cls)); } - else ret->SetObject(nullptr); + else ret->SetPointer(nullptr); return 1; } @@ -10810,7 +10816,7 @@ int BuiltinClassCast(VMValue *param, TArray &defaultparam, int numparam PARAM_PROLOGUE; PARAM_CLASS(from, DObject); PARAM_CLASS(to, DObject); - ACTION_RETURN_OBJECT(from && to && from->IsDescendantOf(to) ? from : nullptr); + ACTION_RETURN_POINTER(from && to && from->IsDescendantOf(to) ? from : nullptr); } ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 6757a2382..56aaf25df 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -505,7 +505,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) default: if (cls != nullptr) { - func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); + func = dyn_cast(cls->FindSymbol(identifier, true)); // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult) diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index 7b31336fd..ea1c50ee4 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -964,7 +964,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) FName name(propname, true); if (name != NAME_None) { - auto propp = dyn_cast(bag.Info->Symbols.FindSymbol(name, true)); + auto propp = dyn_cast(bag.Info->FindSymbol(name, true)); if (propp != nullptr) { DispatchScriptProperty(sc, propp, (AActor *)bag.Info->Defaults, bag); diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 12684a30b..3aa4c5afb 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -97,7 +97,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - auto f = dyn_cast(RUNTIME_CLASS(AActor)->Symbols.FindSymbol("A_CallSpecial", false)); + auto f = dyn_cast(RUNTIME_CLASS(AActor)->FindSymbol("A_CallSpecial", false)); assert(f != nullptr); return new FxVMFunctionCall(new FxSelf(sc), f, args, sc, false); } @@ -583,7 +583,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B FName symname = FName(sc.String, true); symname = CheckCastKludges(symname); - PFunction *afd = dyn_cast(bag.Info->Symbols.FindSymbol(symname, true)); + PFunction *afd = dyn_cast(bag.Info->FindSymbol(symname, true)); if (afd != NULL) { FArgumentList args; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 01a79dfc1..7c5608211 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -733,7 +733,7 @@ FieldDesc *FindField(PStruct *cls, const char * string) VMFunction *FindVMFunction(PClass *cls, const char *name) { - auto f = dyn_cast(cls->Symbols.FindSymbol(name, true)); + auto f = dyn_cast(cls->FindSymbol(name, true)); return f == nullptr ? nullptr : f->Variants[0].Implementation; } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index b2a922b46..0d363c2be 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -342,7 +342,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in FName name(propname, true); if (name != NAME_None) { - auto propp = dyn_cast(info->Symbols.FindSymbol(name, true)); + auto propp = dyn_cast(info->FindSymbol(name, true)); if (propp != nullptr) { *((char*)defaults + propp->Variables[0]->Offset) = set ? 1 : 0; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 572e5a422..be7ff8182 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1404,7 +1404,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper { do { - auto f = dyn_cast(type->Symbols.FindSymbol(id->Id, true)); + auto f = dyn_cast(type->FindSymbol(id->Id, true)); if (f == nullptr) { Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); @@ -2113,7 +2113,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro FName name(propname, true); if (name != NAME_None) { - auto propp = dyn_cast(cls->Symbols.FindSymbol(name, true)); + auto propp = dyn_cast(cls->FindSymbol(name, true)); if (propp != nullptr) { DispatchScriptProperty(propp, prop, (AActor *)bag.Info->Defaults, bag); diff --git a/src/virtual.h b/src/virtual.h index a25e543ac..67d950433 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -1,7 +1,7 @@ inline unsigned GetVirtualIndex(PClass *cls, const char *funcname) { // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. - auto sym = dyn_cast(cls->Symbols.FindSymbol(funcname, false)); + auto sym = dyn_cast(cls->FindSymbol(funcname, false)); assert(sym != nullptr); auto VIndex = sym->Variants[0].Implementation->VirtualIndex; return VIndex; From abc4481431367c0dae46b52002573f0f64f4e273 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 13:11:59 +0200 Subject: [PATCH 13/24] - set PointedType to null for PClassPointer to simplify the functions for this class. --- src/dobjtype.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 96314d025..1cf8af53b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1625,10 +1625,7 @@ void PClassPointer::SetPointer(void *base, unsigned offset, TArray *spec bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const { - const PType *pointat = (const PType *)id1; const PClass *classat = (const PClass *)id2; - - assert(pointat->IsKindOf(RUNTIME_CLASS(PClass))); return classat == ClassRestriction; } @@ -1640,8 +1637,7 @@ bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const { - assert(PointedType == RUNTIME_CLASS(PClass)); - id1 = (intptr_t)PointedType; + id1 = 0; id2 = (intptr_t)ClassRestriction; } @@ -1656,11 +1652,11 @@ void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const PClassPointer *NewClassPointer(PClass *restrict) { size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, &bucket); + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, &bucket); if (ptype == nullptr) { ptype = new PClassPointer(restrict); - TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), (intptr_t)RUNTIME_CLASS(PClass), (intptr_t)restrict, bucket); + TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, bucket); } return static_cast(ptype); } From 63eb3e331ed0c54dcdc3036b7b0e534ae708fd93 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 14:40:29 +0200 Subject: [PATCH 14/24] - un-const-ify some functions. --- src/dobjtype.cpp | 20 ++++++++++---------- src/dobjtype.h | 23 +++++++++++------------ src/info.cpp | 2 +- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1cf8af53b..1f327b9c1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -209,7 +209,7 @@ bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const // //========================================================================== -void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) const +void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) { } @@ -219,7 +219,7 @@ void PType::SetDefaultValue(void *base, unsigned offset, TArray // //========================================================================== -void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) const +void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) { } @@ -1068,7 +1068,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const // //========================================================================== -void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const +void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) { if (base != nullptr) new((uint8_t *)base + offset) FString; if (special != nullptr) @@ -1444,7 +1444,7 @@ PObjectPointer::PObjectPointer(PClass *cls, bool isconst) // //========================================================================== -void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) const +void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) { // Add to the list of pointers for this class. special->Push(offset); @@ -1612,7 +1612,7 @@ bool PClassPointer::isCompatible(PType *type) // //========================================================================== -void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) const +void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) { // Class pointers do not get added to FlatPointers because they are released from the GC. } @@ -1829,7 +1829,7 @@ bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const // //========================================================================== -void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) { for (unsigned i = 0; i < ElementCount; ++i) { @@ -1843,7 +1843,7 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray // //========================================================================== -void PArray::SetPointer(void *base, unsigned offset, TArray *special) const +void PArray::SetPointer(void *base, unsigned offset, TArray *special) { for (unsigned i = 0; i < ElementCount; ++i) { @@ -2067,7 +2067,7 @@ void PDynArray::DestroyValue(void *addr) const // //========================================================================== -void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) const +void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray *special) { if (base != nullptr) memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array. if (special != nullptr) @@ -2312,7 +2312,7 @@ PStruct::PStruct(FName name, PTypeBase *outer) // //========================================================================== -void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) const +void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) { for (const PField *field : Fields) { @@ -2329,7 +2329,7 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) const +void PStruct::SetPointer(void *base, unsigned offset, TArray *special) { for (const PField *field : Fields) { diff --git a/src/dobjtype.h b/src/dobjtype.h index 27248e955..c1b93e595 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -123,8 +123,8 @@ public: // 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; - virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL) const; + virtual void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL); + virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL); virtual void SetPointerArray(void *base, unsigned offset, TArray *ptrofs = NULL) const; // Initialize the value, if needed (e.g. strings) @@ -312,7 +312,7 @@ public: 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 *special=NULL) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *special=NULL) override; void InitializeValue(void *addr, const void *def) const override; void DestroyValue(void *addr) const override; }; @@ -427,7 +427,7 @@ public: void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; + void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; PClass *PointedClass() const; }; @@ -444,7 +444,7 @@ public: void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - void SetPointer(void *base, unsigned offset, TArray *special = NULL) const override; + void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; }; @@ -479,8 +479,8 @@ public: 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 *special) const override; - void SetPointer(void *base, unsigned offset, TArray *special) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *special) override; + void SetPointer(void *base, unsigned offset, TArray *special) override; protected: PArray(); @@ -513,7 +513,7 @@ public: 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 SetDefaultValue(void *base, unsigned offset, TArray *specials) 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; @@ -546,7 +546,7 @@ public: TArray Fields; bool HasNativeFields; - // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it. + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. VMFunction *mConstructor = nullptr; VMFunction *mDestructor = nullptr; @@ -555,8 +555,8 @@ public: 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 SetPointer(void *base, unsigned offset, TArray *specials) const override; + void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; + void SetPointer(void *base, unsigned offset, TArray *specials) override; static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); bool ReadFields(FSerializer &ar, void *addr) const; @@ -565,7 +565,6 @@ protected: }; // a native struct will always be abstract and cannot be instantiated. All variables are references. -// In addition, native structs can have methods (but no virtual ones.) class PNativeStruct : public PStruct { DECLARE_CLASS(PNativeStruct, PStruct); diff --git a/src/info.cpp b/src/info.cpp index 71216cc06..4c3777af4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -82,7 +82,7 @@ public: { } - void SetDefaultValue(void *base, unsigned offset, TArray *special) const override + void SetDefaultValue(void *base, unsigned offset, TArray *special) override { if (base != nullptr) new((uint8_t *)base + offset) FActorInfo; if (special != nullptr) From 0d7b7d6ab197ffdfb2f3c0c48db06a8d27bf4ab6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 15:12:41 +0200 Subject: [PATCH 15/24] - merged PStruct and PNativeStruct. There were exactly 4 places in the code that checked for the difference, this is better done with a flag. --- src/dobjtype.cpp | 57 +++++---------------------- src/dobjtype.h | 19 +++------ src/menu/menudef.cpp | 4 +- src/scripting/backend/codegen.cpp | 4 +- src/scripting/backend/codegen.h | 1 + src/scripting/thingdef_data.cpp | 24 +++++------ src/scripting/zscript/zcc_compile.cpp | 13 ++++-- 7 files changed, 40 insertions(+), 82 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 1f327b9c1..98274328e 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -348,8 +348,8 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. - TypeStringStruct = NewNativeStruct("Stringstruct", nullptr); - TypeFont = NewPointer(NewNativeStruct("Font", nullptr)); + TypeStringStruct = NewStruct("Stringstruct", nullptr, true); + TypeFont = NewPointer(NewStruct("Font", nullptr, true)); #ifdef __BIG_ENDIAN__ TypeColorStruct->AddField(NAME_a, TypeUInt8); TypeColorStruct->AddField(NAME_r, TypeUInt8); @@ -1521,7 +1521,7 @@ IMPLEMENT_CLASS(PStatePointer, false, false) PStatePointer::PStatePointer() { mDescriptiveName = "Pointer"; - PointedType = NewNativeStruct(NAME_State, nullptr); + PointedType = NewStruct(NAME_State, nullptr, true); IsConst = true; } @@ -2190,7 +2190,7 @@ PDynArray *NewDynArray(PType *type) break; } - auto backing = NewNativeStruct(backingname, nullptr); + auto backing = NewStruct(backingname, nullptr, true); atype = new PDynArray(type, backing); TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); } @@ -2298,12 +2298,12 @@ PStruct::PStruct() // //========================================================================== -PStruct::PStruct(FName name, PTypeBase *outer) +PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) : PNamedType(name, outer) { - mDescriptiveName.Format("Struct<%s>", name.GetChars()); + mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); Size = 0; - HasNativeFields = false; + isNative = isnative; } //========================================================================== @@ -2483,7 +2483,6 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_ return nullptr; } Fields.Push(field); - HasNativeFields = true; return field; } @@ -2495,57 +2494,19 @@ PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_ // //========================================================================== -PStruct *NewStruct(FName name, PTypeBase *outer) +PStruct *NewStruct(FName name, PTypeBase *outer, bool native) { 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 == nullptr) { - stype = new PStruct(name, outer); + stype = new PStruct(name, outer, native); TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); } return static_cast(stype); } -/* PNativeStruct ****************************************************************/ - -IMPLEMENT_CLASS(PNativeStruct, false, false) - -//========================================================================== -// -// PNativeStruct - Parameterized Constructor -// -//========================================================================== - -PNativeStruct::PNativeStruct(FName name, PTypeBase *outer) - : PStruct(name, outer) -{ - mDescriptiveName.Format("NativeStruct<%s>", name.GetChars()); - Size = 0; - HasNativeFields = true; -} - -//========================================================================== -// -// NewNativeStruct -// Returns a PNativeStruct for the given name and container, making sure not to -// create duplicates. -// -//========================================================================== - -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 == nullptr) - { - stype = new PNativeStruct(name, outer); - TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); - } - return static_cast(stype); -} /* PField *****************************************************************/ diff --git a/src/dobjtype.h b/src/dobjtype.h index c1b93e595..bc5a6bcfd 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -542,10 +542,10 @@ class PStruct : public PNamedType DECLARE_CLASS(PStruct, PNamedType); public: - PStruct(FName name, PTypeBase *outer); + PStruct(FName name, PTypeBase *outer, bool isnative = false); TArray Fields; - bool HasNativeFields; + bool isNative; // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. VMFunction *mConstructor = nullptr; VMFunction *mDestructor = nullptr; @@ -564,14 +564,6 @@ protected: PStruct(); }; -// a native struct will always be abstract and cannot be instantiated. All variables are references. -class PNativeStruct : public PStruct -{ - DECLARE_CLASS(PNativeStruct, PStruct); -public: - PNativeStruct(FName name = NAME_None, PTypeBase *outer = nullptr); -}; - class PPrototype : public PCompoundType { DECLARE_CLASS(PPrototype, PCompoundType); @@ -596,9 +588,9 @@ enum TentativeClass = UINT_MAX, }; -class PClass : public PNativeStruct +class PClass : public PStruct { - DECLARE_CLASS(PClass, PNativeStruct); + DECLARE_CLASS(PClass, PStruct); // We unravel _WITH_META here just as we did for PType. protected: TArray MetaInits; @@ -730,8 +722,7 @@ PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); PEnum *NewEnum(FName name, PTypeBase *outer); -PStruct *NewStruct(FName name, PTypeBase *outer); -PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer); +PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); // Built-in types ----------------------------------------------------------- diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 458a89502..490f8ec65 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -384,7 +384,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) params.Push(desc); start = 2; } - auto TypeCVar = NewPointer(NewNativeStruct("CVar", nullptr)); + auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); // Note that this array may not be reallocated so its initial size must be the maximum possible elements. TArray strings(args.Size()); @@ -753,7 +753,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) TArray params; params.Push(0); - auto TypeCVar = NewPointer(NewNativeStruct("CVar", nullptr)); + auto TypeCVar = NewPointer(NewStruct("CVar", nullptr, true)); // Note that this array may not be reallocated so its initial size must be the maximum possible elements. TArray strings(args.Size()); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index a87e249a8..26e15fe14 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -1772,7 +1772,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) if (fromtype->IsDescendantOf(totype)) goto basereturn; } } - else if (basex->ValueType->IsA(RUNTIME_CLASS(PNativeStruct)) && ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType == basex->ValueType) + else if (basex->IsNativeStruct() && ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType == basex->ValueType) { bool writable; basex->RequestAddress(ctx, &writable); @@ -2493,7 +2493,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) } // Both types are the same so this is ok. } - else if (Right->ValueType->IsA(RUNTIME_CLASS(PNativeStruct)) && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(Base->ValueType)->PointedType == Right->ValueType) + else if (Right->IsNativeStruct() && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(Base->ValueType)->PointedType == Right->ValueType) { // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. // For all other types this is not needed. Structs are not assignable and classes can only exist as references. diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index f1a322d7a..a6aef7523 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -337,6 +337,7 @@ public: bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); } bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PStaticArray))); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); } + bool IsNativeStruct() const { return (ValueType->IsA(RUNTIME_CLASS(PStruct)) && static_cast(ValueType)->isNative); } virtual ExpEmit Emit(VMFunctionBuilder *build); void EmitStatement(VMFunctionBuilder *build); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 7c5608211..c145fd0f5 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -777,11 +777,11 @@ static int fieldcmp(const void * a, const void * b) void InitThingdef() { // Some native types need size and serialization information added before the scripts get compiled. - auto secplanestruct = NewNativeStruct("Secplane", nullptr); + auto secplanestruct = NewStruct("Secplane", nullptr, true); secplanestruct->Size = sizeof(secplane_t); secplanestruct->Align = alignof(secplane_t); - auto sectorstruct = NewNativeStruct("Sector", nullptr); + auto sectorstruct = NewStruct("Sector", nullptr, true); sectorstruct->Size = sizeof(sector_t); sectorstruct->Align = alignof(sector_t); NewPointer(sectorstruct, false)->InstallHandlers( @@ -796,7 +796,7 @@ void InitThingdef() } ); - auto linestruct = NewNativeStruct("Line", nullptr); + auto linestruct = NewStruct("Line", nullptr, true); linestruct->Size = sizeof(line_t); linestruct->Align = alignof(line_t); NewPointer(linestruct, false)->InstallHandlers( @@ -811,7 +811,7 @@ void InitThingdef() } ); - auto sidestruct = NewNativeStruct("Side", nullptr); + auto sidestruct = NewStruct("Side", nullptr, true); sidestruct->Size = sizeof(side_t); sidestruct->Align = alignof(side_t); NewPointer(sidestruct, false)->InstallHandlers( @@ -826,7 +826,7 @@ void InitThingdef() } ); - auto vertstruct = NewNativeStruct("Vertex", nullptr); + auto vertstruct = NewStruct("Vertex", nullptr, true); vertstruct->Size = sizeof(vertex_t); vertstruct->Align = alignof(vertex_t); NewPointer(vertstruct, false)->InstallHandlers( @@ -841,23 +841,23 @@ void InitThingdef() } ); - auto sectorportalstruct = NewNativeStruct("SectorPortal", nullptr); + auto sectorportalstruct = NewStruct("SectorPortal", nullptr, true); sectorportalstruct->Size = sizeof(FSectorPortal); sectorportalstruct->Align = alignof(FSectorPortal); - auto playerclassstruct = NewNativeStruct("PlayerClass", nullptr); + auto playerclassstruct = NewStruct("PlayerClass", nullptr, true); playerclassstruct->Size = sizeof(FPlayerClass); playerclassstruct->Align = alignof(FPlayerClass); - auto playerskinstruct = NewNativeStruct("PlayerSkin", nullptr); + auto playerskinstruct = NewStruct("PlayerSkin", nullptr, true); playerskinstruct->Size = sizeof(FPlayerSkin); playerskinstruct->Align = alignof(FPlayerSkin); - auto teamstruct = NewNativeStruct("Team", nullptr); + auto teamstruct = NewStruct("Team", nullptr, true); teamstruct->Size = sizeof(FTeam); teamstruct->Align = alignof(FTeam); - PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); + PStruct *pstruct = NewStruct("PlayerInfo", nullptr, true); pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); NewPointer(pstruct, false)->InstallHandlers( @@ -872,7 +872,7 @@ void InitThingdef() } ); - auto fontstruct = NewNativeStruct("FFont", nullptr); + auto fontstruct = NewStruct("FFont", nullptr, true); fontstruct->Size = sizeof(FFont); fontstruct->Align = alignof(FFont); NewPointer(fontstruct, false)->InstallHandlers( @@ -887,7 +887,7 @@ void InitThingdef() } ); - auto wbplayerstruct = NewNativeStruct("WBPlayerStruct", nullptr); + auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true); wbplayerstruct->Size = sizeof(wbplayerstruct_t); wbplayerstruct->Align = alignof(wbplayerstruct_t); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index be7ff8182..50eb2c396 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -513,7 +513,7 @@ void ZCCCompiler::CreateStructTypes() } else if (s->strct->Flags & ZCC_Native) { - s->strct->Type = NewNativeStruct(s->NodeName(), outer); + s->strct->Type = NewStruct(s->NodeName(), outer, true); } else { @@ -1315,7 +1315,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel Error(field, "The member variable '%s.%s' has not been exported from the executable.", type == nullptr? "" : type->TypeName.GetChars(), FName(name->Name).GetChars()); } // For native structs a size check cannot be done because they normally have no size. But for a native reference they are still fine. - else if (thisfieldtype->Size != ~0u && fd->FieldSize != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && !thisfieldtype->IsA(RUNTIME_CLASS(PNativeStruct))) + else if (thisfieldtype->Size != ~0u && fd->FieldSize != ~0u && thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0 && + (!thisfieldtype->IsA(RUNTIME_CLASS(PStruct)) || !static_cast(thisfieldtype)->isNative)) { Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type == nullptr ? "" : type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); } @@ -1702,10 +1703,14 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo { if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - if (ptype->IsKindOf(RUNTIME_CLASS(PNativeStruct))) // native structs and classes cannot be instantiated, they always get used as reference. + else if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) // classes cannot be instantiated at all, they always get used as references. + { + return NewPointer(ptype, type->isconst); + } + else if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)) && static_cast(ptype)->isNative) // native structs and classes cannot be instantiated, they always get used as reference. { if (!nativetype) return NewPointer(ptype, type->isconst); - if (!ptype->IsKindOf(RUNTIME_CLASS(PClass))) return ptype; // instantiation of native structs. Only for internal use. + return ptype; // instantiation of native structs. Only for internal use. } if (!nativetype) return ptype; } From d8d7dc973c7797ac2817982afc9608c4b59e9711 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 12 Apr 2017 17:15:12 +0300 Subject: [PATCH 16/24] Added check for selected item in save/load menu https://mantis.zdoom.org/view.php?id=570 --- wadsrc/static/zscript/menu/loadsavemenu.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/menu/loadsavemenu.txt b/wadsrc/static/zscript/menu/loadsavemenu.txt index 2154e1015..7fe354317 100644 --- a/wadsrc/static/zscript/menu/loadsavemenu.txt +++ b/wadsrc/static/zscript/menu/loadsavemenu.txt @@ -387,7 +387,7 @@ class LoadSaveMenu : ListMenu { if (ev.Type == UIEvent.Type_KeyDown) { - if (Selected < manager.SavegameCount()) + if (Selected != -1 && Selected < manager.SavegameCount()) { switch (ev.KeyChar) { From 20a9f17a158c4d37101dfd4b6177cb423290aa7a Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 12 Apr 2017 17:40:17 +0300 Subject: [PATCH 17/24] Fixed handling of count parameter's default value in Array.Delete() https://mantis.zdoom.org/view.php?id=571 --- src/scripting/backend/dynarrays.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scripting/backend/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp index 0152c6520..fecb3185a 100644 --- a/src/scripting/backend/dynarrays.cpp +++ b/src/scripting/backend/dynarrays.cpp @@ -97,7 +97,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_I8, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I8); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -200,7 +200,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_I16, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I16); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -303,7 +303,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_I32, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_I32); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -406,7 +406,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_F32, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_F32); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -509,7 +509,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_F64, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_F64); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -612,7 +612,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_Ptr, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_Ptr); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } @@ -716,7 +716,7 @@ DEFINE_ACTION_FUNCTION(FDynArray_String, Delete) { PARAM_SELF_STRUCT_PROLOGUE(FDynArray_String); PARAM_INT(index); - PARAM_INT(count); + PARAM_INT_DEF(count); self->Delete(index, count); return 0; } From 96631e88082aa4b5d9645214a275f73daa4dab62 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 17:21:13 +0200 Subject: [PATCH 18/24] - make PClass not inherit from PStruct. Having these two types related can cause problems with detection in the compiler because for some parts they need quite different handling. Common handling for the fields has been moved into PSymbolTable but overall redundancy was quite minor as both types share surprisingly little functionality. --- src/dobjtype.cpp | 208 ++++++++------------------ src/dobjtype.h | 26 ++-- src/scripting/backend/codegen.cpp | 34 ++--- src/scripting/backend/codegen.h | 6 +- src/scripting/symbols.cpp | 78 +++++++++- src/scripting/symbols.h | 10 +- src/scripting/thingdef.cpp | 6 +- src/scripting/thingdef.h | 10 +- src/scripting/thingdef_data.cpp | 4 +- src/scripting/zscript/zcc_compile.cpp | 54 ++++--- src/scripting/zscript/zcc_compile.h | 20 +-- src/scripting/zscript/zcc_parser.h | 2 +- 12 files changed, 221 insertions(+), 237 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 98274328e..b9ad1e57d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -438,17 +438,17 @@ PBasicType::PBasicType(unsigned int size, unsigned int align) IMPLEMENT_CLASS(PCompoundType, true, false) -/* PNamedType *************************************************************/ +/* PContainerType *************************************************************/ -IMPLEMENT_CLASS(PNamedType, true, false) +IMPLEMENT_CLASS(PContainerType, true, false) //========================================================================== // -// PNamedType :: IsMatch +// PContainerType :: IsMatch // //========================================================================== -bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const +bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const { const DObject *outer = (const DObject *)id1; FName name = (ENamedName)(intptr_t)id2; @@ -458,11 +458,11 @@ bool PNamedType::IsMatch(intptr_t id1, intptr_t id2) const //========================================================================== // -// PNamedType :: GetTypeIDs +// PContainerType :: GetTypeIDs // //========================================================================== -void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const { id1 = (intptr_t)Outer; id2 = TypeName; @@ -2280,6 +2280,25 @@ PMap *NewMap(PType *keytype, PType *valuetype) IMPLEMENT_CLASS(PStruct, false, false) +//========================================================================== +// +// WriteFields +// +//========================================================================== + +static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields) +{ + for (unsigned i = 0; i < fields.Size(); ++i) + { + const PField *field = fields[i]; + // Skip fields without or with native serialization + if (!(field->Flags & (VARF_Transient | VARF_Meta))) + { + field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); + } + } +} + //========================================================================== // // PStruct - Default Constructor @@ -2299,7 +2318,7 @@ PStruct::PStruct() //========================================================================== PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) -: PNamedType(name, outer) +: PContainerType(name, outer) { mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); Size = 0; @@ -2365,72 +2384,13 @@ bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const { if (ar.BeginObject(key)) { - bool ret = ReadFields(ar, addr); + bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); ar.EndObject(); return ret; } return false; } -//========================================================================== -// -// PStruct :: WriteFields STATIC -// -//========================================================================== - -void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArray &fields) -{ - for (unsigned i = 0; i < fields.Size(); ++i) - { - const PField *field = fields[i]; - // Skip fields without or with native serialization - if (!(field->Flags & (VARF_Transient|VARF_Meta))) - { - field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); - } - } -} - -//========================================================================== -// -// PStruct :: ReadFields -// -//========================================================================== - -bool PStruct::ReadFields(FSerializer &ar, void *addr) const -{ - bool readsomething = false; - bool foundsomething = false; - const char *label; - while ((label = ar.GetKey())) - { - foundsomething = true; - - const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); - if (sym == nullptr) - { - DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", - label, TypeName.GetChars()); - } - else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) - { - DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", - label, TypeName.GetChars()); - } - else if ((static_cast(sym)->Flags & (VARF_Transient | VARF_Meta))) - { - DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n", - label, TypeName.GetChars()); - } - else - { - readsomething |= static_cast(sym)->Type->ReadValue(ar, nullptr, - (uint8_t *)addr + static_cast(sym)->Offset); - } - } - return readsomething || !foundsomething; -} - //========================================================================== // // PStruct :: AddField @@ -2442,25 +2402,8 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const PField *PStruct::AddField(FName name, PType *type, uint32_t flags) { - PField *field = new PField(name, type, flags); - - // The new field is added to the end of this struct, alignment permitting. - field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); - - // Enlarge this struct to enclose the new field. - Size = unsigned(field->Offset + type->Size); - - // This struct's alignment is the same as the largest alignment of any of - // its fields. - Align = MAX(Align, type->Align); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); - + auto field = Symbols.AddField(name, type, flags, Size, &Align); + if (field != nullptr) Fields.Push(field); return field; } @@ -2699,7 +2642,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * key.Format("class:%s", type->TypeName.GetChars()); if (ar.BeginObject(key.GetChars())) { - PStruct::WriteFields(ar, addr, type->Fields); + WriteFields(ar, addr, type->Fields); ar.EndObject(); } break; @@ -2708,15 +2651,6 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * } } -void PClass::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginObject(key)) - { - RecurseWriteFields(this, ar, addr); - ar.EndObject(); - } -} - // Same as WriteValue, but does not create a new object in the serializer // This is so that user variables do not contain unnecessary subblocks. void PClass::WriteAllFields(FSerializer &ar, const void *addr) const @@ -2726,21 +2660,10 @@ void PClass::WriteAllFields(FSerializer &ar, const void *addr) const //========================================================================== // -// PClass :: ReadValue +// PClass :: ReadAllFields // //========================================================================== -bool PClass::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginObject(key)) - { - bool ret = ReadAllFields(ar, addr); - ar.EndObject(); - return ret; - } - return true; -} - bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { bool readsomething = false; @@ -2778,7 +2701,7 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const { if (ar.BeginObject(nullptr)) { - readsomething |= type->ReadFields(ar, addr); + readsomething |= type->Symbols.ReadFields(ar, addr, DescriptiveName()); ar.EndObject(); } } @@ -3358,39 +3281,6 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) return type; } -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new metadata field to the end of a struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PClass::AddMetaField(FName name, PType *type, uint32_t flags) -{ - PField *field = new PField(name, type, flags); - - // The new field is added to the end of this struct, alignment permitting. - field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1); - - // Enlarge this struct to enclose the new field. - MetaSize = unsigned(field->Offset + type->Size); - - // This struct's alignment is the same as the largest alignment of any of - // its fields. - Align = MAX(Align, type->Align); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); - - return field; -} - //========================================================================== // // PClass :: AddField @@ -3399,10 +3289,11 @@ PField *PClass::AddMetaField(FName name, PType *type, uint32_t flags) PField *PClass::AddField(FName name, PType *type, uint32_t flags) { + PField *field; if (!(flags & VARF_Meta)) { unsigned oldsize = Size; - PField *field = Super::AddField(name, type, flags); + field = Symbols.AddField(name, type, flags, Size); // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before @@ -3412,23 +3303,42 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) Defaults = (uint8_t *)M_Realloc(Defaults, Size); memset(Defaults + oldsize, 0, Size - oldsize); } - return field; } else { + // Same as above, but a different data storage. unsigned oldsize = MetaSize; - PField *field = AddMetaField(name, type, flags); + field = Symbols.AddField(name, type, flags, MetaSize); - // Only initialize the defaults if they have already been created. - // For ZScript this is not the case, it will first define all fields before - // setting up any defaults for any class. if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { Meta = (uint8_t *)M_Realloc(Meta, MetaSize); memset(Meta + oldsize, 0, MetaSize - oldsize); } - return field; } + if (field != nullptr) Fields.Push(field); + return field; +} + +//========================================================================== +// +// PClass :: AddNativeField +// +// This looks the same as the struct version but that will change later. +// +//========================================================================== + +PField *PClass::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + PField *field = new PField(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue); + + if (Symbols.AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + Fields.Push(field); + return field; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index bc5a6bcfd..0b776e503 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -216,22 +216,24 @@ class PCompoundType : public PType DECLARE_ABSTRACT_CLASS(PCompoundType, PType); }; -class PNamedType : public PCompoundType +class PContainerType : public PCompoundType { - DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); + DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType); public: PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name - PNamedType() : Outer(NULL) { + PContainerType() : Outer(NULL) { mDescriptiveName = "NamedType"; } - PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { + PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { mDescriptiveName = name.GetChars(); } virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; + virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; }; // Basic types -------------------------------------------------------------- @@ -537,9 +539,9 @@ protected: PMap(); }; -class PStruct : public PNamedType +class PStruct : public PContainerType { - DECLARE_CLASS(PStruct, PNamedType); + DECLARE_CLASS(PStruct, PContainerType); public: PStruct(FName name, PTypeBase *outer, bool isnative = false); @@ -558,8 +560,6 @@ public: void SetDefaultValue(void *base, unsigned offset, TArray *specials) override; void SetPointer(void *base, unsigned offset, TArray *specials) override; - static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields); - bool ReadFields(FSerializer &ar, void *addr) const; protected: PStruct(); }; @@ -588,20 +588,17 @@ enum TentativeClass = UINT_MAX, }; -class PClass : public PStruct +class PClass : public PContainerType { - DECLARE_CLASS(PClass, PStruct); + DECLARE_CLASS(PClass, PContainerType); // We unravel _WITH_META here just as we did for PType. protected: TArray MetaInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits); void SetSuper(); - PField *AddMetaField(FName name, PType *type, uint32_t flags); public: - 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; bool ReadAllFields(FSerializer &ar, void *addr) const; void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); @@ -625,6 +622,7 @@ public: bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility TArray Virtuals; // virtual function table FName SourceLumpName; + TArray Fields; void (*ConstructNative)(void *); @@ -635,6 +633,8 @@ public: DObject *CreateNew(); PClass *CreateDerivedClass(FName name, unsigned int size); PField *AddField(FName name, PType *type, uint32_t flags=0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; + void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 26e15fe14..f54ccf1f8 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -114,7 +114,7 @@ FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret if (fnc != nullptr) Class = fnc->OwningClass; } -FCompileContext::FCompileContext(PNamespace *cg, PStruct *cls, bool fromdecorate) +FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate) : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg) { } @@ -200,14 +200,14 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) } } -static PStruct *FindStructType(FName name, FCompileContext &ctx) +static PContainerType *FindContainerType(FName name, FCompileContext &ctx) { auto sym = ctx.Class->Symbols.FindSymbol(name, true); if (sym == nullptr) sym = ctx.CurGlobals->Symbols.FindSymbol(name, true); if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - return dyn_cast(type->Type); + return dyn_cast(type->Type); } return nullptr; } @@ -224,7 +224,7 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) return nullptr; } -bool isActor(PStruct *type) +bool isActor(PContainerType *type) { auto cls = dyn_cast(type); return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; @@ -6121,7 +6121,7 @@ foundit: // //========================================================================== -FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classctx, FxExpression *&object, PStruct *objtype) +FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *classctx, FxExpression *&object, PContainerType *objtype) { PSymbol *sym; PSymbolTable *symtbl; @@ -6269,7 +6269,7 @@ FxMemberIdentifier::~FxMemberIdentifier() FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { - PStruct *ccls = nullptr; + PContainerType *ccls = nullptr; CHECKRESOLVED(); if (Object->ExprType == EFX_Identifier) @@ -6277,7 +6277,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) auto id = static_cast(Object)->Identifier; // If the left side is a class name for a static member function call it needs to be resolved manually // because the resulting value type would cause problems in nearly every other place where identifiers are being used. - ccls = FindStructType(id, ctx); + ccls = FindContainerType(id, ctx); if (ccls != nullptr) { static_cast(Object)->noglobal = true; @@ -6398,9 +6398,9 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Object->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { - auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); + auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); delete this; return ret; } @@ -7023,7 +7023,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PPointer *ptrtype = dyn_cast(classx->ValueType); - if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PContainerType))) { ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object"); delete this; @@ -7925,12 +7925,12 @@ FxMemberFunctionCall::~FxMemberFunctionCall() FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { - PStruct *cls; + PContainerType *cls = nullptr; bool staticonly = false; bool novirtual = false; bool isreadonly = false; - PStruct *ccls = nullptr; + PContainerType *ccls = nullptr; if (ctx.Class == nullptr) { @@ -7957,7 +7957,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) // because the resulting value type would cause problems in nearly every other place where identifiers are being used. // [ZZ] substitute ccls for String internal type. if (id == NAME_String) ccls = TypeStringStruct; - else ccls = FindStructType(id, ctx); + else ccls = FindContainerType(id, ctx); if (ccls != nullptr) static_cast(Self)->noglobal = true; } @@ -8228,7 +8228,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; - if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) { @@ -8243,7 +8243,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } - cls = static_cast(ptype); + cls = static_cast(ptype); } else { @@ -8825,9 +8825,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { - if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast(type)->IsA(RUNTIME_CLASS(PStruct))) + if (type == ArgList[i]->ValueType && type->IsA(RUNTIME_CLASS(PPointer)) && static_cast(type)->PointedType->IsA(RUNTIME_CLASS(PStruct))) { - // trying to pass a struct reference as a struct refg + // trying to pass a struct reference as a struct reference. This must preserve the type. } else { diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index a6aef7523..35831c958 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -78,7 +78,7 @@ struct FCompileContext FxCompoundStatement *Block = nullptr; PPrototype *ReturnProto; PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.) - PStruct *Class; // The type of the owning class. + PContainerType *Class; // The type of the owning class. bool FromDecorate; // DECORATE must silence some warnings and demote some errors. int StateIndex; // index in actor's state table for anonymous functions, otherwise -1 (not used by DECORATE which pre-resolves state indices) int StateCount; // amount of states an anoymous function is being used on (must be 1 for state indices to be allowed.) @@ -90,7 +90,7 @@ struct FCompileContext FString VersionString; FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver); - FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants! + FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); @@ -373,7 +373,7 @@ public: FxIdentifier(FName i, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); - FxExpression *ResolveMember(FCompileContext&, PStruct*, FxExpression*&, PStruct*); + FxExpression *ResolveMember(FCompileContext&, PContainerType*, FxExpression*&, PContainerType*); }; diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 41ca4a1a8..8b641ac55 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -36,6 +36,8 @@ #include #include "dobject.h" #include "i_system.h" +#include "templates.h" +#include "serializer.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -102,7 +104,7 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TA assert(proto->ArgumentTypes.Size() > 0); auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); assert(selftypeptr != nullptr); - variant.SelfClass = dyn_cast(selftypeptr->PointedType); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); assert(variant.SelfClass != nullptr); } else @@ -238,6 +240,78 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) // //========================================================================== +PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align) +{ + PField *field = new PField(name, type, flags); + + // The new field is added to the end of this struct, alignment permitting. + field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); + + // Enlarge this struct to enclose the new field. + Size = unsigned(field->Offset + type->Size); + + // This struct's alignment is the same as the largest alignment of any of + // its fields. + if (Align != nullptr) + { + *Align = MAX(*Align, type->Align); + } + + if (AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + return field; +} + +//========================================================================== +// +// PClass :: ReadFields +// +// This will need some changes later. +//========================================================================== + +bool PSymbolTable::ReadFields(FSerializer &ar, void *addr, const char *TypeName) const +{ + bool readsomething = false; + bool foundsomething = false; + const char *label; + while ((label = ar.GetKey())) + { + foundsomething = true; + + const PSymbol *sym = FindSymbol(FName(label, true), false); + if (sym == nullptr) + { + DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", + label, TypeName); + } + else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) + { + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", + label, TypeName); + } + else if ((static_cast(sym)->Flags & (VARF_Transient | VARF_Meta))) + { + DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n", + label, TypeName); + } + else + { + readsomething |= static_cast(sym)->Type->ReadValue(ar, nullptr, + (uint8_t *)addr + static_cast(sym)->Offset); + } + } + return readsomething || !foundsomething; +} + +//========================================================================== +// +// +// +//========================================================================== + void PSymbolTable::RemoveSymbol(PSymbol *sym) { auto mysym = Symbols.CheckKey(sym->SymbolName); @@ -387,7 +461,7 @@ void RemoveUnusedSymbols() { for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) { - if (ty->IsKindOf(RUNTIME_CLASS(PStruct))) + if (ty->IsKindOf(RUNTIME_CLASS(PContainerType))) { auto it = ty->Symbols.GetIterator(); PSymbolTable::MapType::Pair *pair; diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 648462168..f21ec749e 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -10,7 +10,7 @@ class VMFunction; class PType; class PPrototype; struct ZCC_TreeNode; -class PStruct; +class PContainerType; // Symbol information ------------------------------------------------------- @@ -175,15 +175,15 @@ public: TArray ArgNames; // we need the names to access them later when the function gets compiled. uint32_t Flags; int UseFlags; - PStruct *SelfClass; + PContainerType *SelfClass; }; TArray Variants; - PStruct *OwningClass = nullptr; + PContainerType *OwningClass = nullptr; unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags); int GetImplicitArgs(); - PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} + PFunction(PContainerType *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {} }; // A symbol table ----------------------------------------------------------- @@ -215,6 +215,8 @@ struct PSymbolTable // a symbol with the same name is already in the table. This symbol is // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); + PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr); + bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const; // Similar to AddSymbol but always succeeds. Returns the symbol that used // to be in the table with this name, if any. diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 0fbac19b9..4eb0098dd 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -101,7 +101,7 @@ FScriptPosition & GetStateSource(FState *state) // //========================================================================== -void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, uint32_t funcflags, int useflags) +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags) { // Must be called before adding any other arguments. assert(args == nullptr || args->Size() == 0); @@ -154,7 +154,7 @@ void SetImplicitArgs(TArray *args, TArray *argflags, TArray rets(1); TArray args; @@ -184,7 +184,7 @@ PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, i // //========================================================================== -PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error) +PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error) { // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 7517283cf..d727623b4 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -148,8 +148,8 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -AFuncDesc *FindFunction(PStruct *cls, const char * string); -FieldDesc *FindField(PStruct *cls, const char * string); +AFuncDesc *FindFunction(PContainerType *cls, const char * string); +FieldDesc *FindField(PContainerType *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, PNamespace *resolvenspc = nullptr); @@ -159,9 +159,9 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, uint32_t funcflags, int useflags); -PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); -PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags); +PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *returntype, int flags); +PFunction *FindClassMemberFunction(PContainerType *cls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error); void CreateDamageFunction(PNamespace *ns, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c145fd0f5..fe3a35933 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -667,7 +667,7 @@ static int CompareClassNames(const Desc& a, const Desc& b) // //========================================================================== -AFuncDesc *FindFunction(PStruct *cls, const char * string) +AFuncDesc *FindFunction(PContainerType *cls, const char * string) { int min = 0, max = AFTable.Size() - 1; @@ -698,7 +698,7 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string) // //========================================================================== -FieldDesc *FindField(PStruct *cls, const char * string) +FieldDesc *FindField(PContainerType *cls, const char * string) { int min = 0, max = FieldTable.Size() - 1; const char * cname = cls ? cls->TypeName.GetChars() : ""; diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 50eb2c396..9ebed3c6b 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -75,7 +75,7 @@ const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx) return AST.Strings.Alloc(static_cast(ex)->GetValue().GetString())->GetChars(); } -int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) +int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls) { FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxIntCast(ConvertNode(node), false); @@ -89,7 +89,7 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PStruct *cls) return static_cast(ex)->GetValue().GetInt(); } -FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PStruct *cls) +FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls) { FCompileContext ctx(OutNamespace, cls, false); FxExpression *ex = new FxStringCast(ConvertNode(node)); @@ -641,7 +641,7 @@ void ZCCCompiler::CreateClassTypes() { Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); } - else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->Type()->ParentClass->TypeName.GetChars()); + else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); } catch (CRecoverableError &err) { @@ -689,7 +689,7 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::Side_Play); } - c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) + c->ClassType()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -746,7 +746,7 @@ void ZCCCompiler::CreateClassTypes() // Link the tree node tables. We only can do this after we know the class relations. for (auto cc : Classes) { - if (cc->Type() == cd->Type()->ParentClass) + if (cc->ClassType() == cd->ClassType()->ParentClass) { cd->TreeNodes.SetParentTable(&cc->TreeNodes); break; @@ -769,7 +769,7 @@ void ZCCCompiler::CreateClassTypes() // //========================================================================== -void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot) +void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot) { for (auto c : Constants) { @@ -1155,7 +1155,7 @@ void ZCCCompiler::CompileAllFields() } for (unsigned i = 0; i < Classes.Size(); i++) { - auto type = Classes[i]->Type(); + auto type = Classes[i]->ClassType(); if (type->Size == TentativeClass) { @@ -1167,7 +1167,7 @@ void ZCCCompiler::CompileAllFields() else { // Inherit the size of the parent class - type->Size = Classes[i]->Type()->ParentClass->Size; + type->Size = Classes[i]->ClassType()->ParentClass->Size; } } if (type->TypeName == NAME_Actor) @@ -1175,8 +1175,8 @@ void ZCCCompiler::CompileAllFields() assert(type->MetaSize == 0); AddActorInfo(type); // AActor needs the actor info manually added to its meta data before adding any scripted fields. } - else if (Classes[i]->Type()->ParentClass) - type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize; + else if (Classes[i]->ClassType()->ParentClass) + type->MetaSize = Classes[i]->ClassType()->ParentClass->MetaSize; else type->MetaSize = 0; @@ -1207,7 +1207,7 @@ void ZCCCompiler::CompileAllFields() // //========================================================================== -bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) +bool ZCCCompiler::CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) { while (Fields.Size() > 0) { @@ -1372,7 +1372,7 @@ void ZCCCompiler::CompileAllProperties() for (auto c : Classes) { if (c->Properties.Size() > 0) - CompileProperties(c->Type(), c->Properties, c->Type()->TypeName); + CompileProperties(c->ClassType(), c->Properties, c->Type()->TypeName); } } @@ -1727,7 +1727,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo // //========================================================================== -PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls) +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls) { TArray indices; @@ -2189,28 +2189,26 @@ void ZCCCompiler::InitDefaults() for (auto c : Classes) { // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. - if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) { if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars()); - if (c->Type()->ParentClass) + if (c->ClassType()->ParentClass) { - auto ti = static_cast(c->Type()); - FString mename = ti->TypeName.GetChars(); - + auto ti = static_cast(c->ClassType()); ti->InitializeDefaults(); } } else { // This should never happen. - if (c->Type()->Defaults != nullptr) + if (c->ClassType()->Defaults != nullptr) { Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars()); } // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. - else if (c->Type()->ParentClass->Defaults == nullptr && c->Type() != RUNTIME_CLASS(AActor)) + else if (c->ClassType()->ParentClass->Defaults == nullptr && c->ClassType() != RUNTIME_CLASS(AActor)) { - Error(c->cls, "Parent class %s of %s is not initialized", c->Type()->ParentClass->TypeName.GetChars(), c->Type()->TypeName.GetChars()); + Error(c->cls, "Parent class %s of %s is not initialized", c->ClassType()->ParentClass->TypeName.GetChars(), c->ClassType()->TypeName.GetChars()); } else { @@ -2295,7 +2293,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool do { auto type = DetermineType(c->Type(), f, f->Name, t, false, false); - if (type->IsKindOf(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + if (type->IsKindOf(RUNTIME_CLASS(PContainerType)) && type != TypeVector2 && type != TypeVector3) { // structs and classes only get passed by pointer. type = NewPointer(type); @@ -2749,9 +2747,9 @@ void ZCCCompiler::InitFunctions() for (auto c : Classes) { // cannot be done earlier because it requires the parent class to be processed by this code, too. - if (c->Type()->ParentClass != nullptr) + if (c->ClassType()->ParentClass != nullptr) { - c->Type()->Virtuals = c->Type()->ParentClass->Virtuals; + c->ClassType()->Virtuals = c->ClassType()->ParentClass->Virtuals; } for (auto f : c->Functions) { @@ -2847,7 +2845,7 @@ void ZCCCompiler::CompileStates() for (auto c : Classes) { - if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) { if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); continue; @@ -2855,7 +2853,7 @@ void ZCCCompiler::CompileStates() FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; - statedef.MakeStateDefines(ValidateActor(c->Type()->ParentClass)); + statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); int numframes = 0; for (auto s : c->States) @@ -3050,7 +3048,7 @@ void ZCCCompiler::CompileStates() } try { - GetDefaultByType(c->Type())->Finalize(statedef); + GetDefaultByType(c->ClassType())->Finalize(statedef); } catch (CRecoverableError &err) { @@ -3065,7 +3063,7 @@ void ZCCCompiler::CompileStates() // //========================================================================== -FxExpression *ZCCCompiler::ConvertAST(PStruct *cls, ZCC_TreeNode *ast) +FxExpression *ZCCCompiler::ConvertAST(PContainerType *cls, ZCC_TreeNode *ast) { ConvertClass = cls; // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 9d54f925b..acfbc6b15 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -41,7 +41,7 @@ struct ZCC_StructWork return strct->NodeName; } - PStruct *Type() + PContainerType *Type() { return strct->Type; } @@ -64,7 +64,7 @@ struct ZCC_ClassWork : public ZCC_StructWork Outer = nullptr; } - PClass *Type() + PClass *ClassType() { return static_cast(strct->Type); } @@ -79,7 +79,7 @@ struct ZCC_PropertyWork struct ZCC_ConstantWork { ZCC_ConstantDef *node; - PStruct *cls; + PContainerType *cls; PSymbolTable *Outputtable; ExpVal constval; }; @@ -94,25 +94,25 @@ public: private: const char * GetStringConst(FxExpression *ex, FCompileContext &ctx); - int IntConstFromNode(ZCC_TreeNode *node, PStruct *cls); - FString StringConstFromNode(ZCC_TreeNode *node, PStruct *cls); + int IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls); + FString StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls); void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); void CreateStructTypes(); void CreateClassTypes(); - void CopyConstants(TArray &dest, TArray &Constants, PStruct *cls, PSymbolTable *ot); + void CopyConstants(TArray &dest, TArray &Constants, PContainerType *cls, PSymbolTable *ot); void CompileAllConstants(); void AddConstant(ZCC_ConstantWork &constant); bool CompileConstant(ZCC_ConstantWork *def); void CompileArrays(ZCC_StructWork *work); void CompileAllFields(); - bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); + bool CompileFields(PContainerType *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); void CompileAllProperties(); bool CompileProperties(PClass *type, TArray &Properties, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); - PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PStruct *cls); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls); PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype); void InitDefaults(); @@ -143,12 +143,12 @@ private: void Error(ZCC_TreeNode *node, const char *msg, ...) GCCPRINTF(3,4); void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); - FxExpression *ConvertAST(PStruct *cclass, ZCC_TreeNode *ast); + FxExpression *ConvertAST(PContainerType *cclass, ZCC_TreeNode *ast); FxExpression *ConvertNode(ZCC_TreeNode *node); FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head); DObject *Outer; - PStruct *ConvertClass; // class type to be used when resoving symbols while converting an AST + PContainerType *ConvertClass; // class type to be used when resoving symbols while converting an AST PSymbolTable *GlobalTreeNodes; PNamespace *OutNamespace; ZCC_AST &AST; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 29c6ec20c..22742ac56 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -195,7 +195,7 @@ struct ZCC_Struct : ZCC_NamedNode { VM_UWORD Flags; ZCC_TreeNode *Body; - PStruct *Type; + PContainerType *Type; VersionInfo Version; }; From 8dc11317dd72d0da5f18dbe0a85261444cd5c7d3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 17:42:10 +0200 Subject: [PATCH 19/24] - Moved WriteFields into SymbolTable as well. --- src/dobjtype.cpp | 23 ++--------------------- src/scripting/symbols.cpp | 26 +++++++++++++++++++++++++- src/scripting/symbols.h | 1 + 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b9ad1e57d..bca6d7f10 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2280,25 +2280,6 @@ PMap *NewMap(PType *keytype, PType *valuetype) IMPLEMENT_CLASS(PStruct, false, false) -//========================================================================== -// -// WriteFields -// -//========================================================================== - -static void WriteFields(FSerializer &ar, const void *addr, const TArray &fields) -{ - for (unsigned i = 0; i < fields.Size(); ++i) - { - const PField *field = fields[i]; - // Skip fields without or with native serialization - if (!(field->Flags & (VARF_Transient | VARF_Meta))) - { - field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); - } - } -} - //========================================================================== // // PStruct - Default Constructor @@ -2369,7 +2350,7 @@ void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) cons { if (ar.BeginObject(key)) { - WriteFields(ar, addr, Fields); + Symbols.WriteFields(ar, addr); ar.EndObject(); } } @@ -2642,7 +2623,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * key.Format("class:%s", type->TypeName.GetChars()); if (ar.BeginObject(key.GetChars())) { - WriteFields(ar, addr, type->Fields); + type->Symbols.WriteFields(ar, addr); ar.EndObject(); } break; diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 8b641ac55..57b520113 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -265,11 +265,35 @@ PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned return field; } +//========================================================================== +// +// PClass :: WriteFields +// +//========================================================================== + +void PSymbolTable::WriteFields(FSerializer &ar, const void *addr, const void *def) const +{ + auto it = MapType::ConstIterator(Symbols); + MapType::ConstPair *pair; + + while (it.NextPair(pair)) + { + const PField *field = dyn_cast(pair->Value); + // Skip fields without or with native serialization + if (field && !(field->Flags & (VARF_Transient | VARF_Meta))) + { + // todo: handle defaults in WriteValue + //auto defp = def == nullptr ? nullptr : (const uint8_t *)def + field->Offset; + field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const uint8_t *)addr + field->Offset); + } + } +} + + //========================================================================== // // PClass :: ReadFields // -// This will need some changes later. //========================================================================== bool PSymbolTable::ReadFields(FSerializer &ar, void *addr, const char *TypeName) const diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index f21ec749e..bc9053cb3 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -217,6 +217,7 @@ struct PSymbolTable PSymbol *AddSymbol (PSymbol *sym); PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr); bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const; + void WriteFields(FSerializer &ar, const void *addr, const void *def = nullptr) const; // Similar to AddSymbol but always succeeds. Returns the symbol that used // to be in the table with this name, if any. From afd6743965d45d49dd76894c06a666ab6a235de4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 18:29:58 +0200 Subject: [PATCH 20/24] - moved AddNativeField to PSymbolTable, too. --- src/dobjtype.cpp | 40 ++++++++++++++------------------------- src/dobjtype.h | 1 - src/scripting/symbols.cpp | 21 ++++++++++++++++++++ src/scripting/symbols.h | 1 + 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index bca6d7f10..68b300871 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2314,9 +2314,12 @@ PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) { - for (const PField *field : Fields) + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) { - if (!(field->Flags & VARF_Transient)) + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) { field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); } @@ -2331,9 +2334,12 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) { - for (const PField *field : Fields) + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) { - if (!(field->Flags & VARF_Transient)) + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) { field->Type->SetPointer(base, unsigned(offset + field->Offset), special); } @@ -2383,9 +2389,7 @@ bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const PField *PStruct::AddField(FName name, PType *type, uint32_t flags) { - auto field = Symbols.AddField(name, type, flags, Size, &Align); - if (field != nullptr) Fields.Push(field); - return field; + return Symbols.AddField(name, type, flags, Size, &Align); } //========================================================================== @@ -2399,15 +2403,7 @@ PField *PStruct::AddField(FName name, PType *type, uint32_t flags) PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) { - PField *field = new PField(name, type, flags|VARF_Native|VARF_Transient, address, bitvalue); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); - return field; + return Symbols.AddNativeField(name, type, address, flags, bitvalue); } //========================================================================== @@ -3305,20 +3301,12 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) // // PClass :: AddNativeField // -// This looks the same as the struct version but that will change later. -// //========================================================================== PField *PClass::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) { - PField *field = new PField(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue); - - if (Symbols.AddSymbol(field) == nullptr) - { // name is already in use - field->Destroy(); - return nullptr; - } - Fields.Push(field); + auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); + if (field != nullptr) Fields.Push(field); return field; } diff --git a/src/dobjtype.h b/src/dobjtype.h index 0b776e503..823c43e2a 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -546,7 +546,6 @@ class PStruct : public PContainerType public: PStruct(FName name, PTypeBase *outer, bool isnative = false); - TArray Fields; bool isNative; // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. VMFunction *mConstructor = nullptr; diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 57b520113..5fc59f7b0 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -265,6 +265,27 @@ PField *PSymbolTable::AddField(FName name, PType *type, uint32_t flags, unsigned return field; } +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new native field to the struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PSymbolTable::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + PField *field = new PField(name, type, flags | VARF_Native | VARF_Transient, address, bitvalue); + + if (AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + return field; +} + //========================================================================== // // PClass :: WriteFields diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index bc9053cb3..649e5584a 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -216,6 +216,7 @@ struct PSymbolTable // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); PField *AddField(FName name, PType *type, uint32_t flags, unsigned &Size, unsigned *Align = nullptr); + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue); bool ReadFields(FSerializer &ar, void *addr, const char *TypeName) const; void WriteFields(FSerializer &ar, const void *addr, const void *def = nullptr) const; From fc9e304189f296b1aeece5e85183f1646cf6b8ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 22:46:49 +0200 Subject: [PATCH 21/24] - separated class descriptors from VM types. Combining these two groups of data has been the cause of many hard to detect errors because it allowed liberal casting between types that are used for completely different things. --- src/d_dehacked.cpp | 7 +- src/dobjtype.cpp | 285 +++++++++++---------- src/dobjtype.h | 56 ++-- src/dsectoreffect.cpp | 16 +- src/dsectoreffect.h | 27 +- src/info.cpp | 23 -- src/info.h | 1 - src/p_conversation.cpp | 2 +- src/p_things.cpp | 2 +- src/p_user.cpp | 2 +- src/scripting/backend/codegen.cpp | 168 ++++++------ src/scripting/backend/scopebarrier.cpp | 4 +- src/scripting/decorate/thingdef_exp.cpp | 2 +- src/scripting/decorate/thingdef_parse.cpp | 13 +- src/scripting/decorate/thingdef_states.cpp | 2 +- src/scripting/thingdef.cpp | 12 +- src/scripting/thingdef_data.cpp | 63 +++-- src/scripting/thingdef_properties.cpp | 2 +- src/scripting/vm/vm.h | 8 +- src/scripting/vm/vmexec.h | 2 +- src/scripting/zscript/zcc_compile.cpp | 96 +++---- src/scripting/zscript/zcc_compile.h | 2 +- src/scripting/zscript/zcc_parser.h | 2 +- wadsrc/static/zscript/base.txt | 24 +- 24 files changed, 428 insertions(+), 393 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 31a5ec784..2b7f6999a 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -3034,7 +3034,8 @@ void FinishDehPatch () subclass = static_cast(dehtype->CreateDerivedClass(typeNameBuilder, dehtype->Size)); } while (subclass == nullptr); - + NewClassType(subclass); // This needs a VM type to work as intended. + AActor *defaults2 = GetDefaultByType (subclass); memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); @@ -3152,7 +3153,7 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType) int lex = memcmp (DehSpriteMappings[mid].Sprite, sprites[self->sprite].name, 4); if (lex == 0) { - ACTION_RETURN_OBJECT(PClass::FindActor(DehSpriteMappings[mid].ClassName)); + ACTION_RETURN_POINTER(PClass::FindActor(DehSpriteMappings[mid].ClassName)); } else if (lex < 0) { @@ -3163,6 +3164,6 @@ DEFINE_ACTION_FUNCTION(ADehackedPickup, DetermineType) max = mid - 1; } } - ACTION_RETURN_OBJECT(nullptr); + ACTION_RETURN_POINTER(nullptr); } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 68b300871..c1d36b3db 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -68,6 +68,7 @@ FMemArena ClassDataAllocator(32768); // use this for all static class data that FTypeTable TypeTable; TArray PClass::AllClasses; +TMap PClass::ClassMap; TArray PClass::FunctionPtrList; bool PClass::bShutdown; bool PClass::bVMOperational; @@ -96,6 +97,7 @@ PStruct *TypeStringStruct; PPointer *TypeNullPtr; PPointer *TypeVoidPtr; + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // A harmless non-nullptr FlatPointer for classes without pointers. @@ -1353,8 +1355,16 @@ PPointer::PPointer() PPointer::PPointer(PType *pointsat, bool isconst) : PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) { - mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); - mVersion = pointsat->mVersion; + if (pointsat != nullptr) + { + mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); + mVersion = pointsat->mVersion; + } + else + { + mDescriptiveName = "Pointer"; + mVersion = 0; + } loadOp = OP_LP; storeOp = OP_SP; moveOp = OP_MOVEA; @@ -1431,7 +1441,7 @@ IMPLEMENT_CLASS(PObjectPointer, false, false) //========================================================================== PObjectPointer::PObjectPointer(PClass *cls, bool isconst) - : PPointer(cls, isconst) + : PPointer(cls->VMType, isconst) { loadOp = OP_LO; // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. @@ -1484,28 +1494,32 @@ bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) con PPointer *NewPointer(PType *type, bool isconst) { - if (type->IsKindOf(RUNTIME_CLASS(PClass))) + auto cp = dyn_cast(type); + if (cp) return NewPointer(cp->Descriptor, isconst); + + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) { - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PObjectPointer(static_cast(type), isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } - else + return static_cast(ptype); +} + +PPointer *NewPointer(PClass *cls, bool isconst) +{ + assert(cls->VMType != nullptr); + + auto type = cls->VMType; + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) { - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PPointer(type, isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); + ptype = new PObjectPointer(cls, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } + return static_cast(ptype); } /* PStatePointer **********************************************************/ @@ -1562,13 +1576,13 @@ IMPLEMENT_CLASS(PClassPointer,false, false) //========================================================================== PClassPointer::PClassPointer(PClass *restrict) -: PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) +: PPointer(restrict->VMType), ClassRestriction(restrict) { if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); else mDescriptiveName = "ClassPointer"; loadOp = OP_LP; storeOp = OP_SP; - mVersion = restrict->mVersion; + mVersion = restrict->VMType->mVersion; } //========================================================================== @@ -1614,7 +1628,6 @@ bool PClassPointer::isCompatible(PType *type) void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) { - // Class pointers do not get added to FlatPointers because they are released from the GC. } //========================================================================== @@ -2590,7 +2603,71 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PClass *****************************************************************/ -IMPLEMENT_CLASS(PClass, false, false) +IMPLEMENT_CLASS(PClassType, false, false) + +//========================================================================== +// +// +// +//========================================================================== + +PClassType::PClassType(PClass *cls) +{ + assert(cls->VMType == nullptr); + Descriptor = cls; + TypeName = cls->TypeName; + if (cls->ParentClass != nullptr) + { + ParentType = cls->ParentClass->VMType; + assert(ParentType != nullptr); + Symbols.SetParentTable(&ParentType->Symbols); + } + cls->VMType = this; + mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); +} + +//========================================================================== +// +// PClass :: AddField +// +//========================================================================== + +PField *PClassType::AddField(FName name, PType *type, uint32_t flags) +{ + return Descriptor->AddField(name, type, flags); +} + +//========================================================================== +// +// PClass :: AddNativeField +// +//========================================================================== + +PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); + if (field != nullptr) Descriptor->Fields.Push(field); + return field; +} + +//========================================================================== +// +// +// +//========================================================================== + +PClassType *NewClassType(PClass *cls) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, &bucket); + if (ptype == nullptr) + { + ptype = new PClassType(cls); + TypeTable.AddType(ptype, RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, bucket); + } + return static_cast(ptype); +} + //========================================================================== // @@ -2619,7 +2696,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * key.Format("class:%s", type->TypeName.GetChars()); if (ar.BeginObject(key.GetChars())) { - type->Symbols.WriteFields(ar, addr); + type->VMType->Symbols.WriteFields(ar, addr); ar.EndObject(); } break; @@ -2666,19 +2743,11 @@ bool PClass::ReadAllFields(FSerializer &ar, void *addr) const if (type != nullptr) { // Only read it if the type is related to this one. - const PClass *parent; - for (parent = this; parent != nullptr; parent = parent->ParentClass) - { - if (parent == type) - { - break; - } - } - if (parent != nullptr) + if (IsDescendantOf(type)) { if (ar.BeginObject(nullptr)) { - readsomething |= type->Symbols.ReadFields(ar, addr, DescriptiveName()); + readsomething |= type->VMType->Symbols.ReadFields(ar, addr, type->TypeName.GetChars()); ar.EndObject(); } } @@ -2738,15 +2807,6 @@ void PClass::StaticInit () // I'm not sure if this is really necessary to maintain any sort of sync. qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); - // Set all symbol table relations here so that they are valid right from the start. - for (auto c : AllClasses) - { - if (c->ParentClass != nullptr) - { - c->Symbols.SetParentTable(&c->ParentClass->Symbols); - } - } - } //========================================================================== @@ -2785,7 +2845,6 @@ void PClass::StaticShutdown () // This must be done before the type table is taken down. for (auto cls : AllClasses) { - Printf("Processing %s\n", cls->TypeName.GetChars()); cls->DestroyMeta(cls->Meta); } // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. @@ -2814,16 +2873,6 @@ void PClass::StaticShutdown () void PClass::StaticBootstrap() { - 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. - cls->InsertIntoHash(); - - // Create parent objects before we go so that these definitions are complete. - cls->ParentClass = PClass::RegistrationInfo.ParentType->RegisterClass(); } //========================================================================== @@ -2834,20 +2883,6 @@ void PClass::StaticBootstrap() PClass::PClass() { - Size = sizeof(DObject); - ParentClass = nullptr; - Pointers = nullptr; - FlatPointers = nullptr; - ArrayPointers = nullptr; - HashNext = nullptr; - Defaults = nullptr; - bRuntimeClass = false; - bExported = false; - bDecorateClass = false; - ConstructNative = nullptr; - Meta = nullptr; - mDescriptiveName = "Class"; - PClass::AllClasses.Push(this); } @@ -2882,12 +2917,6 @@ PClass::~PClass() PClass *ClassReg::RegisterClass() { - static ClassReg *const metaclasses[] = - { - &PClass::RegistrationInfo, - &PClassActor::RegistrationInfo, - }; - // Skip classes that have already been registered if (MyClass != nullptr) { @@ -2895,18 +2924,7 @@ PClass *ClassReg::RegisterClass() } // Add type to list - PClass *cls; - - if (MetaClassNum >= countof(metaclasses)) - { - assert(0 && "Class registry has an invalid meta class identifier"); - } - - if (metaclasses[MetaClassNum]->MyClass == nullptr) - { // Make sure the meta class is already registered before registering this one - metaclasses[MetaClassNum]->RegisterClass(); - } - cls = static_cast(metaclasses[MetaClassNum]->MyClass->CreateNew()); + PClass *cls = new PClass; SetupClass(cls); cls->InsertIntoHash(); @@ -2934,7 +2952,7 @@ void ClassReg::SetupClass(PClass *cls) cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; - cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); + //cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); } //========================================================================== @@ -2947,17 +2965,18 @@ void ClassReg::SetupClass(PClass *cls) void PClass::InsertIntoHash () { - size_t bucket; - PType *found; - - found = TypeTable.FindType(RUNTIME_CLASS(PClass), 0, TypeName, &bucket); - if (found != nullptr) + auto k = ClassMap.CheckKey(TypeName); + if (k != nullptr) { // This type has already been inserted I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } else { - TypeTable.AddType(this, RUNTIME_CLASS(PClass), 0, TypeName, bucket); + ClassMap[TypeName] = this; + } + if (IsDescendantOf(RUNTIME_CLASS(AActor))) + { + PClassActor::AllActorClasses.Push(static_cast(this)); } } @@ -2995,7 +3014,8 @@ PClass *PClass::FindClass (FName zaname) { return nullptr; } - return static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), 0, zaname, nullptr)); + auto k = ClassMap.CheckKey(zaname); + return k ? *k : nullptr; } //========================================================================== @@ -3104,10 +3124,7 @@ void PClass::Derive(PClass *newclass, FName name) newclass->bRuntimeClass = true; newclass->ParentClass = this; newclass->ConstructNative = ConstructNative; - newclass->Symbols.SetParentTable(&this->Symbols); newclass->TypeName = name; - newclass->mDescriptiveName.Format("Class<%s>", name.GetChars()); - newclass->mVersion = mVersion; newclass->MetaSize = MetaSize; } @@ -3175,26 +3192,33 @@ void PClass::InitializeDefaults() } } - if (bRuntimeClass) + if (VMType != nullptr) // purely internal classes have no symbol table { - // Copy parent values from the parent defaults. - assert(ParentClass != nullptr); - if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + if (bRuntimeClass) + { + // Copy parent values from the parent defaults. + assert(ParentClass != nullptr); + if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits); + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + { + field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + } + } + } + if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta)) + if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) { - field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); } } } - if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits); - for (const PField *field : Fields) + else { - if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta)) - { - field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits); - } + Printf("VM-less class %s\n", TypeName.GetChars()); } } @@ -3235,7 +3259,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) } else { - type = static_cast(GetClass()->CreateNew()); + type = new PClass; notnew = false; } @@ -3245,11 +3269,12 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) type->Size = size; if (size != TentativeClass) { + NewClassType(type); type->InitializeDefaults(); type->Virtuals = Virtuals; } else - type->ObjectFlags &= OF_Transient; + type->bOptional = false; if (!notnew) { @@ -3270,7 +3295,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) if (!(flags & VARF_Meta)) { unsigned oldsize = Size; - field = Symbols.AddField(name, type, flags, Size); + field = VMType->Symbols.AddField(name, type, flags, Size); // Only initialize the defaults if they have already been created. // For ZScript this is not the case, it will first define all fields before @@ -3285,7 +3310,7 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) { // Same as above, but a different data storage. unsigned oldsize = MetaSize; - field = Symbols.AddField(name, type, flags, MetaSize); + field = VMType->Symbols.AddField(name, type, flags, MetaSize); if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr) { @@ -3297,19 +3322,6 @@ PField *PClass::AddField(FName name, PType *type, uint32_t flags) return field; } -//========================================================================== -// -// PClass :: AddNativeField -// -//========================================================================== - -PField *PClass::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); - if (field != nullptr) Fields.Push(field); - return field; -} - //========================================================================== // // PClass :: FindClassTentative @@ -3325,21 +3337,17 @@ PClass *PClass::FindClassTentative(FName name) { return nullptr; } - size_t bucket; - PType *found = TypeTable.FindType(RUNTIME_CLASS(PClass), - /*FIXME:Outer*/0, name, &bucket); + PClass *found = FindClass(name); + if (found != nullptr) return found; - if (found != nullptr) - { - return static_cast(found); - } - PClass *type = static_cast(GetClass()->CreateNew()); + PClass *type = new PClass; DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); Derive(type, name); type->Size = TentativeClass; - TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket); + + InsertIntoHash(); return type; } @@ -3392,7 +3400,8 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto) PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const { - return Symbols.FindSymbol(symname, searchparents); + if (VMType == nullptr) return nullptr; + return VMType->Symbols.FindSymbol(symname, searchparents); } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index 823c43e2a..dfb362a81 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -587,12 +587,24 @@ enum TentativeClass = UINT_MAX, }; -class PClass : public PContainerType +class PClassType : public PContainerType +{ + DECLARE_CLASS(PClassType, PContainerType); + +private: + +public: + PClass *Descriptor; + PClassType *ParentType; + + PClassType(PClass *cls = nullptr); + PField *AddField(FName name, PType *type, uint32_t flags = 0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; +}; + +class PClass { - DECLARE_CLASS(PClass, PContainerType); - // We unravel _WITH_META here just as we did for PType. protected: - TArray MetaInits; void Derive(PClass *newclass, FName name); void InitializeSpecials(void *addr, void *defaults, TArray PClass::*Inits); void SetSuper(); @@ -602,26 +614,32 @@ public: void InitializeDefaults(); int FindVirtualIndex(FName name, PPrototype *proto); PSymbol *FindSymbol(FName symname, bool searchparents) const; + PField *AddField(FName name, PType *type, uint32_t flags); static void StaticInit(); static void StaticShutdown(); static void StaticBootstrap(); // Per-class information ------------------------------------- - TArray SpecialInits; - 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. - uint8_t *Defaults; - uint8_t *Meta; // Per-class static script data - unsigned MetaSize; - bool bRuntimeClass; // class was defined at run-time, not compile-time - bool bExported; // This type has been declared in a script - bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility + PClass *ParentClass = nullptr; // the class this class derives from + const size_t *Pointers = nullptr; // object pointers defined by this class *only* + const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default + const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers. + uint8_t *Defaults = nullptr; + uint8_t *Meta = nullptr; // Per-class static script data + unsigned Size = sizeof(DObject); + unsigned MetaSize = 0; + FName TypeName; + FName SourceLumpName; + bool bRuntimeClass = false; // class was defined at run-time, not compile-time + bool bDecorateClass = false; // may be subject to some idiosyncracies due to DECORATE backwards compatibility + bool bAbstract = false; + bool bOptional = false; TArray Virtuals; // virtual function table - FName SourceLumpName; + TArray MetaInits; + TArray SpecialInits; TArray Fields; + PClassType *VMType = nullptr; void (*ConstructNative)(void *); @@ -631,13 +649,10 @@ public: void InsertIntoHash(); DObject *CreateNew(); PClass *CreateDerivedClass(FName name, unsigned int size); - PField *AddField(FName name, PType *type, uint32_t flags=0) override; - PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; void InitializeActorInfo(); void BuildFlatPointers(); void BuildArrayPointers(); - void InitMeta(); void DestroySpecials(void *addr); void DestroyMeta(void *addr); const PClass *NativeClass() const; @@ -687,6 +702,7 @@ public: static void FindFunction(VMFunction **pptr, FName cls, FName func); PClass *FindClassTentative(FName name); + static TMap ClassMap; static TArray AllClasses; static TArray FunctionPtrList; @@ -719,10 +735,12 @@ PArray *NewArray(PType *type, unsigned int count); PStaticArray *NewStaticArray(PType *type); PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type, bool isconst = false); +PPointer *NewPointer(PClass *type, bool isconst = false); PClassPointer *NewClassPointer(PClass *restrict); PEnum *NewEnum(FName name, PTypeBase *outer); PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); +PClassType *NewClassType(PClass *cls); // Built-in types ----------------------------------------------------------- diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index e02af8ccf..ec257a310 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -75,16 +75,12 @@ void DSectorEffect::Serialize(FSerializer &arc) DEFINE_FIELD(DSectorEffect, m_Sector) -IMPLEMENT_CLASS(DMover, false, true) +IMPLEMENT_CLASS(DMover, true, true) IMPLEMENT_POINTERS_START(DMover) IMPLEMENT_POINTER(interpolation) IMPLEMENT_POINTERS_END -DMover::DMover () -{ -} - DMover::DMover (sector_t *sector) : DSectorEffect (sector) { @@ -112,11 +108,8 @@ void DMover::StopInterpolation(bool force) } } -IMPLEMENT_CLASS(DMovingFloor, false, false) +IMPLEMENT_CLASS(DMovingFloor, true, false) -DMovingFloor::DMovingFloor () -{ -} DMovingFloor::DMovingFloor (sector_t *sector) : DMover (sector) @@ -125,11 +118,8 @@ DMovingFloor::DMovingFloor (sector_t *sector) interpolation = sector->SetInterpolation(sector_t::FloorMove, true); } -IMPLEMENT_CLASS(DMovingCeiling, false, false) +IMPLEMENT_CLASS(DMovingCeiling, true, false) -DMovingCeiling::DMovingCeiling () -{ -} DMovingCeiling::DMovingCeiling (sector_t *sector, bool interpolate) : DMover (sector) diff --git a/src/dsectoreffect.h b/src/dsectoreffect.h index bdd2aa713..e583a85cd 100644 --- a/src/dsectoreffect.h +++ b/src/dsectoreffect.h @@ -25,16 +25,17 @@ protected: class DMover : public DSectorEffect { - DECLARE_CLASS (DMover, DSectorEffect) + DECLARE_ABSTRACT_CLASS (DMover, DSectorEffect) HAS_OBJECT_POINTERS -public: +protected: DMover (sector_t *sector); - void StopInterpolation(bool force = false); -protected: + TObjPtr interpolation; -private: +public: + void StopInterpolation(bool force = false); + protected: - DMover (); + DMover () {} void Serialize(FSerializer &arc); void OnDestroy() override; @@ -42,20 +43,18 @@ protected: class DMovingFloor : public DMover { - DECLARE_CLASS (DMovingFloor, DMover) -public: - DMovingFloor (sector_t *sector); + DECLARE_ABSTRACT_CLASS (DMovingFloor, DMover) protected: - DMovingFloor (); + DMovingFloor (sector_t *sector); + DMovingFloor() {} }; class DMovingCeiling : public DMover { - DECLARE_CLASS (DMovingCeiling, DMover) -public: - DMovingCeiling (sector_t *sector, bool interpolate = true); + DECLARE_ABSTRACT_CLASS (DMovingCeiling, DMover) protected: - DMovingCeiling (); + DMovingCeiling (sector_t *sector, bool interpolate = true); + DMovingCeiling () {} }; #endif //__DSECTOREFFECT_H__ diff --git a/src/info.cpp b/src/info.cpp index 4c3777af4..7f677bf3a 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -231,8 +231,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); } -IMPLEMENT_CLASS(PClassActor, false, false) - //========================================================================== // // PClassActor :: StaticInit STATIC @@ -286,27 +284,6 @@ void PClassActor::StaticSetActorNums() } } -//========================================================================== -// -// PClassActor Constructor -// -//========================================================================== - -PClassActor::PClassActor() -{ - AllActorClasses.Push(this); -} - -//========================================================================== -// -// PClassActor Destructor -// -//========================================================================== - -PClassActor::~PClassActor() -{ -} - //========================================================================== // // PClassActor :: SetReplacement diff --git a/src/info.h b/src/info.h index 907b9a3b2..01a1a3f47 100644 --- a/src/info.h +++ b/src/info.h @@ -288,7 +288,6 @@ struct FActorInfo class PClassActor : public PClass { - DECLARE_CLASS(PClassActor, PClass); protected: public: static void StaticInit (); diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0e734479a..08399fe49 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -639,7 +639,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) return; // Don't take the sigil. - if (itemtype->GetClass()->TypeName == NAME_Sigil) + if (itemtype->TypeName == NAME_Sigil) return; player->mo->TakeInventory(itemtype, amount); diff --git a/src/p_things.cpp b/src/p_things.cpp index da6f56cac..ac105f4ee 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -526,7 +526,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType) { PARAM_PROLOGUE; PARAM_INT(num); - ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); + ACTION_RETURN_POINTER(P_GetSpawnableType(num)); } struct MapinfoSpawnItem diff --git a/src/p_user.cpp b/src/p_user.cpp index 2a4f000e8..f1f1b31f2 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1242,7 +1242,7 @@ void APlayerPawn::CheckWeaponSwitch(PClassActor *ammotype) DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) { PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_OBJECT(ammotype, PClassActor); + PARAM_POINTER(ammotype, PClassActor); self->CheckWeaponSwitch(ammotype); return 0; } diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index f54ccf1f8..7d731eb5f 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -56,7 +56,7 @@ #include "w_wad.h" #include "math/cmath.h" -inline PClass *PObjectPointer::PointedClass() const { return static_cast(PointedType); } +inline PClass *PObjectPointer::PointedClass() const { return static_cast(PointedType)->Descriptor; } extern FRandom pr_exrandom; FMemArena FxAlloc(65536); @@ -219,15 +219,16 @@ static PClass *FindClassType(FName name, FCompileContext &ctx) if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) { auto type = static_cast(sym); - return dyn_cast(type->Type); + auto ctype = dyn_cast(type->Type); + if (ctype) return ctype->Descriptor; } return nullptr; } bool isActor(PContainerType *type) { - auto cls = dyn_cast(type); - return cls ? cls->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; + auto cls = dyn_cast(type); + return cls ? cls->Descriptor->IsDescendantOf(RUNTIME_CLASS(AActor)) : false; } //========================================================================== @@ -1762,13 +1763,13 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // this is not yet ready and does not get assigned to actual values. } */ - else if (ValueType->IsKindOf(RUNTIME_CLASS(PClass))) // this should never happen because the VM doesn't handle plain class types - just pointers + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) // this should never happen because the VM doesn't handle plain class types - just pointers { - if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) + if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClassType))) { // class types are only compatible if the base type is a descendant of the result type. - auto fromtype = static_cast(basex->ValueType); - auto totype = static_cast(ValueType); + auto fromtype = static_cast(basex->ValueType)->Descriptor; + auto totype = static_cast(ValueType)->Descriptor; if (fromtype->IsDescendantOf(totype)) goto basereturn; } } @@ -5148,7 +5149,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) if (val->isConstant()) { auto cls = static_cast(static_cast(val)->GetValue().GetPointer()); - if (cls->ObjectFlags & OF_Abstract) + if (cls->bAbstract) { ScriptPosition.Message(MSG_ERROR, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); delete this; @@ -5159,7 +5160,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) int outerside = ctx.Function && ctx.Function->Variants.Size() ? FScopeBarrier::SideFromFlags(ctx.Function->Variants[0].Flags) : FScopeBarrier::Side_Virtual; if (outerside == FScopeBarrier::Side_Virtual) outerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags); - int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" { ScriptPosition.Message(MSG_ERROR, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); @@ -6125,7 +6126,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * { PSymbol *sym; PSymbolTable *symtbl; - bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass)); + bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClassType)); if (Identifier == NAME_Default) { @@ -6179,8 +6180,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * object = nullptr; return nullptr; } - PClass* cls_ctx = dyn_cast(classctx); - PClass* cls_target = dyn_cast(objtype); + auto cls_ctx = dyn_cast(classctx); + auto cls_target = dyn_cast(objtype); // [ZZ] neither PSymbol, PField or PSymbolTable have the necessary information. so we need to do the more complex check here. if (vsym->Flags & VARF_Protected) { @@ -6194,7 +6195,7 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * } // find the class that declared this field. - PClass* p = cls_target; + auto p = cls_target; while (p) { if (&p->Symbols == symtbl) @@ -6203,10 +6204,10 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType * break; } - p = p->ParentClass; + p = p->ParentType; } - if (!cls_ctx->IsDescendantOf(cls_target)) + if (!cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars()); delete object; @@ -6358,32 +6359,29 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { - if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + PSymbol *sym; + if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) { - PSymbol *sym; - if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return FxConstant::MakeConstant(sym, ScriptPosition); + } + else + { + auto f = dyn_cast(sym); + if (f != nullptr && (f->Flags & (VARF_Static | VARF_ReadOnly | VARF_Meta)) == (VARF_Static | VARF_ReadOnly)) { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + auto x = new FxGlobalVariable(f, ScriptPosition); delete this; - return FxConstant::MakeConstant(sym, ScriptPosition); + return x->Resolve(ctx); } else { - auto f = dyn_cast(sym); - if (f != nullptr && (f->Flags & (VARF_Static | VARF_ReadOnly | VARF_Meta)) == (VARF_Static | VARF_ReadOnly)) - { - auto x = new FxGlobalVariable(f, ScriptPosition); - delete this; - return x->Resolve(ctx); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); - delete this; - return nullptr; - } + ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return nullptr; } } } @@ -7500,9 +7498,9 @@ static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction bool match = (callingself == calledself); if (!match) { - auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); - auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); - match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls); + auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); + auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); + match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->Descriptor->IsDescendantOf(calledselfcls->Descriptor); } if (!match) @@ -7613,7 +7611,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } // [ZZ] validate call - PClass* cls = (PClass*)ctx.Class; int outerflags = 0; if (ctx.Function) { @@ -7626,7 +7623,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) // [ZZ] check this at compile time. this would work for most legit cases. if (innerside == FScopeBarrier::Side_Virtual) { - innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + innerside = FScopeBarrier::SideFromObjectFlags(ctx.Class->ObjectFlags); innerflags = FScopeBarrier::FlagsFromSide(innerside); } FScopeBarrier scopeBarrier(outerflags, innerflags, MethodName.GetChars()); @@ -7702,7 +7699,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } PClass *cls = FindClassType(MethodName, ctx); - if (cls != nullptr && cls->bExported) + if (cls != nullptr) { if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) { @@ -7863,14 +7860,17 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition)) { // [ZZ] allow implicit new() call to mean "create current class instance" - if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClass))) + if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClassType))) { ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct"); delete this; return nullptr; } else if (!ArgList.Size()) - ArgList.Push(new FxConstant((PClass*)ctx.Class, NewClassPointer((PClass*)ctx.Class), ScriptPosition)); + { + auto cls = static_cast(ctx.Class)->Descriptor; + ArgList.Push(new FxConstant(cls, NewClassPointer(cls), ScriptPosition)); + } func = new FxNew(ArgList[0]); ArgList[0] = nullptr; @@ -7967,40 +7967,37 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { if (ccls != nullptr) { - if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + cls = ccls; + staticonly = true; + if (ccls->IsKindOf(RUNTIME_CLASS(PClassType))) { - cls = ccls; - staticonly = true; - if (ccls->IsKindOf(RUNTIME_CLASS(PClass))) + if (ctx.Function == nullptr) { - if (ctx.Function == nullptr) + ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); + delete this; + return nullptr; + } + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + if (clstype != nullptr) + { + novirtual = clstype->Descriptor->IsDescendantOf(static_cast(ccls)->Descriptor); + if (novirtual) { - ScriptPosition.Message(MSG_ERROR, "Unable to call %s from constant declaration", MethodName.GetChars()); - delete this; - return nullptr; - } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); - if (clstype != nullptr) - { - novirtual = clstype->IsDescendantOf(static_cast(ccls)); - if (novirtual) + bool error; + PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); + if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) { - bool error; - PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); - if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) - { - staticonly = false; - novirtual = true; - delete Self; - Self = new FxSelf(ScriptPosition); - Self->ValueType = NewPointer(cls); - } - else novirtual = false; + staticonly = false; + novirtual = true; + delete Self; + Self = new FxSelf(ScriptPosition); + Self->ValueType = NewPointer(cls); } + else novirtual = false; } } - if (!novirtual) goto isresolved; } + if (!novirtual) goto isresolved; } } @@ -8012,11 +8009,11 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } - auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); if (clstype != nullptr) { // give the node the proper value type now that we know it's properly used. - cls = clstype->ParentClass; + cls = clstype->ParentType; Self->ValueType = NewPointer(cls); Self->ExprType = EFX_Self; novirtual = true; // super calls are always non-virtual @@ -8230,7 +8227,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto ptype = static_cast(Self->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PContainerType))) { - if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) + if (ptype->IsKindOf(RUNTIME_CLASS(PClassType)) && MethodName == NAME_GetClass) { if (ArgList.Size() > 0) { @@ -8333,9 +8330,9 @@ isresolved: { if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) { - auto clstype = dyn_cast(ctx.Class); - auto ccls = dyn_cast(cls); - if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) + auto clstype = dyn_cast(ctx.Class); + auto ccls = dyn_cast(cls); + if (clstype == nullptr || ccls == nullptr || !clstype->Descriptor->IsDescendantOf(ccls->Descriptor)) { ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here", cls->TypeName.GetChars(), MethodName.GetChars()); delete this; @@ -9303,7 +9300,7 @@ FxExpression *FxGetClass::Resolve(FCompileContext &ctx) delete this; return nullptr; } - ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)); + ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)->Descriptor); return this; } @@ -10639,7 +10636,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) if (Explicit) cls = FindClassType(clsname, ctx); else cls = PClass::FindClass(clsname); - if (cls == nullptr) + if (cls == nullptr || cls->VMType == nullptr) { /* lax */ // Since this happens in released WADs it must pass without a terminal error... :( @@ -10694,7 +10691,7 @@ int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numpar const PClass *cls = PClass::FindClass(clsname); const PClass *desttype = reinterpret_cast(param[1].a); - if (!cls->IsDescendantOf(desttype)) + if (cls->VMType == nullptr || !cls->IsDescendantOf(desttype)) { // Let the caller check this. Making this an error with a message is only taking away options from the user. cls = nullptr; @@ -10851,7 +10848,9 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); ABORT(ctx.Class); - auto aclass = dyn_cast(ctx.Class); + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); // This expression type can only be used from actors, for everything else it has already produced a compile error. assert(aclass != nullptr && aclass->GetStateCount() > 0); @@ -10927,8 +10926,12 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) Index = new FxIntCast(Index, ctx.FromDecorate); SAFE_RESOLVE(Index, ctx); } - auto aclass = dyn_cast(ctx.Class); + + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto aclass = ValidateActor(vclass->Descriptor); assert(aclass != nullptr && aclass->GetStateCount() > 0); + symlabel = StateLabels.AddPointer(aclass->GetStates() + ctx.StateIndex); ValueType = TypeStateLabel; return this; @@ -10983,7 +10986,10 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) CHECKRESOLVED(); ABORT(ctx.Class); int symlabel; - auto clstype = dyn_cast(ctx.Class); + + auto vclass = dyn_cast(ctx.Class); + assert(vclass != nullptr); + auto clstype = ValidateActor(vclass->Descriptor); if (names[0] == NAME_None) { diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index 29caa2457..f227e0240 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -175,14 +175,14 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) // these are for vmexec.h void FScopeBarrier::ValidateNew(PClass* cls, int outerside) { - int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(cls->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } void FScopeBarrier::ValidateCall(PClass* selftype, VMFunction *calledfunc, int outerside) { - int innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(selftype->VMType->ObjectFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName.GetChars(), FScopeBarrier::StringFromSide(outerside)); } \ No newline at end of file diff --git a/src/scripting/decorate/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp index 56aaf25df..d3acae632 100644 --- a/src/scripting/decorate/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -88,7 +88,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, PNamespace *spc) if (spc) { - FCompileContext ctx(spc, cls, true); + FCompileContext ctx(spc, cls->VMType, true); data = data->Resolve(ctx); } diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index ea1c50ee4..4758aaa23 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -69,9 +69,9 @@ EXTERN_CVAR(Bool, strictdecorate); PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) { - if (parent->mVersion > MakeVersion(2, 0)) + if (parent->VMType->mVersion > MakeVersion(2, 0)) { - sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->GetClass()->TypeName.GetChars(), typeName.GetChars()); + sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->TypeName.GetChars(), typeName.GetChars()); } PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); if (type == nullptr) @@ -101,7 +101,8 @@ PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FN if (type != nullptr) { // [ZZ] DECORATE classes are always play - type->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(type->ObjectFlags, FScopeBarrier::Side_Play); + auto vmtype = type->VMType; + vmtype->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(vmtype->ObjectFlags, FScopeBarrier::Side_Play); } return type; @@ -1151,15 +1152,15 @@ static void ParseActor(FScanner &sc, PNamespace *ns) switch (sc.TokenType) { case TK_Const: - ParseConstant (sc, &info->Symbols, info, ns); + ParseConstant (sc, &info->VMType->Symbols, info, ns); break; case TK_Enum: - ParseEnum (sc, &info->Symbols, info, ns); + ParseEnum (sc, &info->VMType->Symbols, info, ns); break; case TK_Var: - ParseUserVariable (sc, &info->Symbols, info, ns); + ParseUserVariable (sc, &info->VMType->Symbols, info, ns); break; case TK_Identifier: diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 3aa4c5afb..a5f48aa6c 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -339,7 +339,7 @@ do_stop: endofstate: if (ScriptCode != nullptr) { - auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags); + auto funcsym = CreateAnonymousFunction(actor->VMType, nullptr, state.UseFlags); state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, bag.Version, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); } int count = bag.statedef.AddStates(&state, statestring, scp); diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 4eb0098dd..14fd21886 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -195,8 +195,8 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func if (symbol != nullptr) { - PClass* cls_ctx = dyn_cast(funccls); - PClass* cls_target = funcsym?dyn_cast(funcsym->OwningClass):nullptr; + auto cls_ctx = dyn_cast(funccls); + auto cls_target = funcsym ? dyn_cast(funcsym->OwningClass) : nullptr; if (funcsym == nullptr) { sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); @@ -206,7 +206,7 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func // private access is only allowed if the symbol table belongs to the class in which the current function is being defined. sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars()); } - else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->IsDescendantOf((PClass*)cls_target))) + else if ((funcsym->Variants[0].Flags & VARF_Protected) && symtable != &funccls->Symbols && (!cls_ctx || !cls_target || !cls_ctx->Descriptor->IsDescendantOf(cls_target->Descriptor))) { sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars()); } @@ -236,7 +236,7 @@ void CreateDamageFunction(PNamespace *OutNamespace, const VersionInfo &ver, PCla else { auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); - auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0); + auto funcsym = CreateAnonymousFunction(info->VMType, TypeSInt32, 0); defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, ver, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); } } @@ -373,6 +373,7 @@ static void CheckStates(PClassActor *obj) //========================================================================== void ParseScripts(); void ParseAllDecorate(); +void SynthesizeFlagFields(); void LoadActors() { @@ -387,6 +388,7 @@ void LoadActors() FScriptPosition::StrictErrors = false; ParseAllDecorate(); + SynthesizeFlagFields(); FunctionBuildList.Build(); @@ -401,7 +403,7 @@ void LoadActors() auto ti = PClassActor::AllActorClasses[i]; if (ti->Size == TentativeClass) { - if (ti->ObjectFlags & OF_Transient) + if (ti->bOptional) { Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); FScriptPosition::WarnCounter++; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index fe3a35933..5bbeb9296 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -67,7 +67,14 @@ static TArray AFTable; static TArray FieldTable; extern int BackbuttonTime; extern float BackbuttonAlpha; -static AWeapon *wpnochg; + +// Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but is used everywhere as a special flag. +// It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' +// is to create a static variable from it that points to an otherwise unused object and reference that in the script. Yuck!!! +// This must point to a valid DObject derived object so that the garbage collector can deal with it. +// The global VM types are the most convenient options here because they get created before the compiler is started and they +// are not exposed in other ways to scripts - and they do not change unless the engine is shut down. +DEFINE_GLOBAL_NAMED(TypeSInt32, wp_nochange); //========================================================================== // @@ -505,6 +512,7 @@ static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(ADynamicLight),DynLightFlagDefs, countof(DynLightFlagDefs), 3 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -890,29 +898,6 @@ void InitThingdef() auto wbplayerstruct = NewStruct("WBPlayerStruct", nullptr, true); wbplayerstruct->Size = sizeof(wbplayerstruct_t); wbplayerstruct->Align = alignof(wbplayerstruct_t); - - - // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. - // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' - // is to create a static variable from it and reference that in the script. Yuck!!! - wpnochg = WP_NOCHANGE; - PField *fieldptr = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); - Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); - - // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. - for (auto &fl : FlagLists) - { - if (fl.Use & 2) - { - for(int i=0;i 0) // skip the deprecated entries in this list - { - const_cast(*fl.Type)->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); - } - } - } - } FAutoSegIterator probe(CRegHead, CRegTail); @@ -980,9 +965,37 @@ void InitThingdef() FieldTable.ShrinkToFit(); qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); } - } +void SynthesizeFlagFields() +{ + // These are needed for inserting the flag symbols + /* + NewClassType(RUNTIME_CLASS(DObject)); + NewClassType(RUNTIME_CLASS(DThinker)); + NewClassType(RUNTIME_CLASS(AActor)); + NewClassType(RUNTIME_CLASS(AInventory)); + NewClassType(RUNTIME_CLASS(AStateProvider)); + NewClassType(RUNTIME_CLASS(AWeapon)); + NewClassType(RUNTIME_CLASS(APlayerPawn)); + NewClassType(RUNTIME_CLASS(ADynamicLight)); + */ + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (auto &fl : FlagLists) + { + auto cls = const_cast(*fl.Type); + if (fl.Use & 2) + { + for (int i = 0; i < fl.NumDefs; i++) + { + if (fl.Defs[i].structoffset > 0) // skip the deprecated entries in this list + { + cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); + } + } + } + } +} DEFINE_ACTION_FUNCTION(DObject, GameType) { PARAM_PROLOGUE; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 0d363c2be..0084c319c 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -92,7 +92,7 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool } if (cls->Size == TentativeClass && optional) { - cls->ObjectFlags |= OF_Transient; // since this flag has no meaning in class types, let's use it for marking the type optional. + cls->bOptional = true; } return static_cast(cls); } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index a0103c83d..d05e33a5f 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -834,10 +834,10 @@ bool AssertObject(void * ob); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); #define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_EXISTS(p) ((p) < numparam) @@ -853,8 +853,8 @@ bool AssertObject(void * ob); #define PARAM_STATE_ACTION_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, stateowner->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, stateowner->GetClass()); } #define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; } #define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; } -#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } -#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } +#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { x = (t::MetaClass*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } +#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index adb0480de..a62627cc4 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -791,7 +791,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) { ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); } - if (cls->ObjectFlags & OF_Abstract) + if (cls->bAbstract) { ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 9ebed3c6b..677b5f11e 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -51,6 +51,8 @@ #include "backend/vmbuilder.h" FSharedStringArena VMStringConstants; +bool isActor(PContainerType *type); + static int GetIntConst(FxExpression *ex, FCompileContext &ctx) { @@ -496,8 +498,8 @@ void ZCCCompiler::CreateStructTypes() s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); if (s->Outer) { - outer = s->Outer; - syms = &s->Outer->Symbols; + outer = s->Outer->VMType; + syms = &s->Outer->VMType->Symbols; } else { @@ -603,7 +605,7 @@ void ZCCCompiler::CreateClassTypes() parent = RUNTIME_CLASS(DObject); } - if (parent != nullptr) + if (parent != nullptr && (parent->VMType != nullptr || c->NodeName() == NAME_Object)) { // The parent exists, we may create a type for this class if (c->cls->Flags & ZCC_Native) @@ -624,7 +626,7 @@ void ZCCCompiler::CreateClassTypes() { DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); } - c->cls->Type = me; + c->cls->Type = NewClassType(me); me->SourceLumpName = *c->cls->SourceName; } else @@ -632,25 +634,33 @@ void ZCCCompiler::CreateClassTypes() // We will never get here if the name is a duplicate, so we can just do the assignment. try { - if (parent->mVersion > mVersion) + if (parent->VMType->mVersion > mVersion) { Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision); } - c->cls->Type = parent->CreateDerivedClass(c->NodeName(), TentativeClass); - if (c->Type() == nullptr) + auto newclass = parent->CreateDerivedClass(c->NodeName(), TentativeClass); + if (newclass == nullptr) { Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); } - else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); + else + { + c->cls->Type = NewClassType(newclass); + DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->ClassType()->ParentClass->TypeName.GetChars()); + } } catch (CRecoverableError &err) { Error(c->cls, "%s", err.GetMessage()); - // create a placeholder so that the compiler can continue looking for errors. c->cls->Type = nullptr; } } - if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName()); + if (c->Type() == nullptr) + { + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = NewClassType(parent->FindClassTentative(c->NodeName())); + } + if (c->cls->Flags & ZCC_Abstract) c->Type()->ObjectFlags |= OF_Abstract; @@ -675,13 +685,13 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI; if (c->cls->Flags & ZCC_Play) c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play; - if (parent->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play + if (parent->VMType->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play { if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play)) { Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars()); } - c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(parent->ObjectFlags)); + c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(parent->VMType->ObjectFlags)); } } else @@ -689,14 +699,13 @@ void ZCCCompiler::CreateClassTypes() c->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(c->Type()->ObjectFlags, FScopeBarrier::Side_Play); } - c->ClassType()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); OrigClasses.Delete(i--); donesomething = true; } - else + else if (c->cls->ParentName != nullptr) { // No base class found. Now check if something in the unprocessed classes matches. // If not, print an error. If something is found let's retry again in the next iteration. @@ -713,7 +722,7 @@ void ZCCCompiler::CreateClassTypes() { Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars()); // create a placeholder so that the compiler can continue looking for errors. - c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -729,7 +738,7 @@ void ZCCCompiler::CreateClassTypes() for (auto c : OrigClasses) { Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); - c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Type = NewClassType(RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName())); c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); OutNamespace->Symbols.AddSymbol(c->cls->Symbol); Classes.Push(c); @@ -753,7 +762,7 @@ void ZCCCompiler::CreateClassTypes() } } - if (cd->cls->Replaces != nullptr && !static_cast(cd->Type())->SetReplacement(cd->cls->Replaces->Id)) + if (cd->cls->Replaces != nullptr && !static_cast(cd->ClassType())->SetReplacement(cd->cls->Replaces->Id)) { Warn(cd->cls, "Replaced type '%s' not found for %s", FName(cd->cls->Replaces->Id).GetChars(), cd->Type()->TypeName.GetChars()); } @@ -1131,7 +1140,7 @@ void ZCCCompiler::CompileAllFields() // We need to search the global class table here because not all children may have a scripted definition attached. for (auto ac : PClass::AllClasses) { - if (ac->ParentClass == c->Type() && ac->Size != TentativeClass) + if (ac->ParentClass != nullptr && ac->ParentClass->VMType == c->Type() && ac->Size != TentativeClass) { // Only set a marker here, so that we can print a better message when the actual fields get added. HasNativeChildren.Insert(ac, true); @@ -1180,7 +1189,7 @@ void ZCCCompiler::CompileAllFields() else type->MetaSize = 0; - if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) + if (CompileFields(type->VMType, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. Classes.Delete(i--); @@ -1423,7 +1432,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &Proper else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars()); fields.ShrinkToFit(); - if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) + if (!type->VMType->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) { Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); } @@ -1648,7 +1657,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n return TypeError; } auto typesym = dyn_cast(sym); - if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClass))) + if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClassType))) { Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); return TypeError; @@ -1658,7 +1667,7 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); return TypeError; } - retval = NewClassPointer(static_cast(typesym->Type)); + retval = NewClassPointer(static_cast(typesym->Type)->Descriptor); } break; } @@ -1703,7 +1712,7 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt, boo { if (!nativetype) return TypeSInt32; // hack this to an integer until we can resolve the enum mess. } - else if (ptype->IsKindOf(RUNTIME_CLASS(PClass))) // classes cannot be instantiated at all, they always get used as references. + else if (ptype->IsKindOf(RUNTIME_CLASS(PClassType))) // classes cannot be instantiated at all, they always get used as references. { return NewPointer(ptype, type->isconst); } @@ -1789,7 +1798,7 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper const char * p = prop->params; auto exp = property->Values; - FCompileContext ctx(OutNamespace, bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info->VMType, false); while (true) { FPropParam conv; @@ -1971,7 +1980,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop } auto exp = property->Values; - FCompileContext ctx(OutNamespace, bag.Info, false); + FCompileContext ctx(OutNamespace, bag.Info->VMType, false); for (auto f : prop->Variables) { void *addr; @@ -2200,20 +2209,21 @@ void ZCCCompiler::InitDefaults() } else { + auto cls = c->ClassType(); // This should never happen. - if (c->ClassType()->Defaults != nullptr) + if (cls->Defaults != nullptr) { - Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars()); + Error(c->cls, "%s already has defaults", cls->TypeName.GetChars()); } // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. - else if (c->ClassType()->ParentClass->Defaults == nullptr && c->ClassType() != RUNTIME_CLASS(AActor)) + else if (cls->ParentClass->Defaults == nullptr && cls != RUNTIME_CLASS(AActor)) { - Error(c->cls, "Parent class %s of %s is not initialized", c->ClassType()->ParentClass->TypeName.GetChars(), c->ClassType()->TypeName.GetChars()); + Error(c->cls, "Parent class %s of %s is not initialized", cls->ParentClass->TypeName.GetChars(), cls->TypeName.GetChars()); } else { // Copy the parent's defaults and meta data. - auto ti = static_cast(c->Type()); + auto ti = static_cast(cls); ti->InitializeDefaults(); @@ -2226,7 +2236,7 @@ void ZCCCompiler::InitDefaults() Baggage bag; #ifdef _DEBUG - bag.ClassName = c->Type()->TypeName; + bag.ClassName = cls->TypeName; #endif bag.Version = mVersion; bag.Namespace = OutNamespace; @@ -2390,7 +2400,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool Error(f, "Action functions cannot be declared UI"); } // Non-Actors cannot have action functions. - if (!c->Type()->IsKindOf(RUNTIME_CLASS(PClassActor))) + if (!isActor(c->Type())) { Error(f, "'Action' can only be used in child classes of Actor"); } @@ -2598,9 +2608,10 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); c->Type()->Symbols.ReplaceSymbol(sym); - auto cls = dyn_cast(c->Type()); + auto vcls = dyn_cast(c->Type()); + auto cls = vcls ? vcls->Descriptor : nullptr; PFunction *virtsym = nullptr; - if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true)); + if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->VMType->Symbols.FindSymbol(FName(f->Name), true)); unsigned vindex = ~0u; if (virtsym != nullptr) { @@ -2644,7 +2655,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; } - PClass *clstype = static_cast(c->Type()); + PClass *clstype = static_cast(c->Type())->Descriptor; if (varflags & VARF_Virtual) { if (sym->Variants[0].Implementation == nullptr) @@ -2666,7 +2677,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool else { auto oldfunc = clstype->Virtuals[vindex]; - auto parentfunc = dyn_cast(clstype->ParentClass->Symbols.FindSymbol(sym->SymbolName, true)); + auto parentfunc = dyn_cast(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)); if (parentfunc && parentfunc->mVersion > mVersion) { Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision); @@ -2798,15 +2809,14 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, in // The actual action function is still needed by DECORATE: if (id->Identifier != NAME_ACS_NamedExecuteWithResult) { - PFunction *afd = dyn_cast(cls->Symbols.FindSymbol(id->Identifier, true)); + PFunction *afd = dyn_cast(cls->VMType->Symbols.FindSymbol(id->Identifier, true)); if (afd != nullptr) { if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) { FArgumentList argumentlist; // We can use this function directly without wrapping it in a caller. - auto selfclass = dyn_cast(afd->Variants[0].SelfClass); - assert(selfclass != nullptr); // non classes are not supposed to get here. + assert(dyn_cast(afd->Variants[0].SelfClass) != nullptr); // non classes are not supposed to get here. int comboflags = afd->Variants[0].UseFlags & StateFlags; if (comboflags == StateFlags) // the function must satisfy all the flags the state requires @@ -2831,7 +2841,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, in } } } - return ConvertAST(cls, af); + return ConvertAST(cls->VMType, af); } //========================================================================== @@ -2889,7 +2899,7 @@ void ZCCCompiler::CompileStates() } else { - flags = static_cast(c->Type())->ActorInfo()->DefaultStateUsage; + flags = static_cast(c->ClassType())->ActorInfo()->DefaultStateUsage; } auto st = s->Body; if (st != nullptr) do @@ -2966,7 +2976,7 @@ void ZCCCompiler::CompileStates() if (sl->Action != nullptr) { - auto code = SetupActionFunction(static_cast(c->Type()), sl->Action, state.UseFlags); + auto code = SetupActionFunction(static_cast(c->ClassType()), sl->Action, state.UseFlags); if (code != nullptr) { auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); @@ -3176,7 +3186,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxNop(*ast); // return something so that the compiler can continue. } auto cls = PClass::FindClass(cc->ClassName); - if (cls == nullptr) + if (cls == nullptr || cls->VMType == nullptr) { Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); return new FxNop(*ast); // return something so that the compiler can continue. diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index acfbc6b15..baa5c89f6 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -66,7 +66,7 @@ struct ZCC_ClassWork : public ZCC_StructWork PClass *ClassType() { - return static_cast(strct->Type); + return static_cast(strct->Type)->Descriptor; } }; diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index 22742ac56..b55fd153b 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -209,7 +209,7 @@ struct ZCC_Class : ZCC_Struct ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; - PClass *CType() { return static_cast(Type); } + PClass *CType() { return static_cast(Type)->Descriptor; } }; struct ZCC_Enum : ZCC_NamedNode diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 0f1195cbf..9defba9de 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -41,6 +41,7 @@ struct _ native // These are the global variables, the struct is only here to av native ui float BackbuttonAlpha; native readonly int Net_Arbitrator; native ui BaseStatusBar StatusBar; + native readonly Weapon WP_NOCHANGE; } @@ -650,7 +651,21 @@ struct StringStruct native native String Filter(); } -class Floor : Thinker native +class SectorEffect : Thinker native +{ + native protected Sector m_Sector; +} + +class Mover : SectorEffect native +{} + +class MovingFloor : Mover native +{} + +class MovingCeiling : Mover native +{} + +class Floor : MovingFloor native { // only here so that some constants and functions can be added. Not directly usable yet. enum EFloor @@ -695,7 +710,7 @@ class Floor : Thinker native native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); } -class Ceiling : Thinker native +class Ceiling : MovingCeiling native { enum ECeiling { @@ -749,11 +764,6 @@ struct LookExParams State seestate; }; -class SectorEffect : Thinker native -{ - native protected Sector m_Sector; -} - class Lighting : SectorEffect native { } From 3e47f00ba0f901c2016c4fb579cb2505bbef893e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 12 Apr 2017 22:57:14 +0200 Subject: [PATCH 22/24] - the new order requires manual deletion of all class descriptors. --- src/dobjtype.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index c1d36b3db..a220e2df6 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2842,11 +2842,10 @@ void PClass::StaticShutdown () p.PendingWeapon = nullptr; } - // This must be done before the type table is taken down. - for (auto cls : AllClasses) - { - cls->DestroyMeta(cls->Meta); - } + // This must be done in two steps because the native classes are not ordered by inheritance, + // so all meta data must be gone before deleting the actual class objects. + for (auto cls : AllClasses) cls->DestroyMeta(cls->Meta); + for (auto cls : AllClasses) delete cls; // Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts. bShutdown = true; TypeTable.Clear(); From 6599e2c4252b09a3aca2b6ab1bf8d25bf0d8def7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 13 Apr 2017 01:12:04 +0200 Subject: [PATCH 23/24] - moved the VM types into their own file and only include it where really needed. --- src/CMakeLists.txt | 1 + src/am_map.cpp | 2 - src/b_bot.cpp | 1 + src/b_game.cpp | 1 + src/c_bind.cpp | 1 + src/c_cmds.cpp | 28 - src/c_console.cpp | 1 + src/c_cvars.cpp | 1 + src/c_dispatch.cpp | 1 + src/d_dehacked.cpp | 1 + src/d_main.cpp | 2 + src/d_netinfo.cpp | 1 + src/dobject.cpp | 5 +- src/dobject.h | 50 +- src/dobjtype.cpp | 2729 +----------------------- src/dobjtype.h | 683 +----- src/doomstat.cpp | 1 - src/dsectoreffect.cpp | 1 + src/dthinker.cpp | 6 +- src/events.cpp | 47 +- src/g_game.cpp | 3 + src/g_inventory/a_keys.cpp | 2 +- src/g_inventory/a_pickups.cpp | 15 +- src/g_inventory/a_weapons.cpp | 18 +- src/g_level.cpp | 6 +- src/g_shared/a_action.cpp | 1 + src/g_shared/a_dynlight.cpp | 3 +- src/g_shared/a_morph.cpp | 9 +- src/g_shared/a_specialspot.cpp | 1 + src/g_shared/shared_hud.cpp | 4 +- src/g_skill.cpp | 1 + src/g_statusbar/sbarinfo.cpp | 2 +- src/g_statusbar/sbarinfo_commands.cpp | 4 +- src/g_statusbar/shared_sbar.cpp | 28 +- src/gi.cpp | 1 + src/gl/textures/gl_texture.cpp | 1 + src/info.cpp | 38 +- src/info.h | 6 +- src/m_cheat.cpp | 8 +- src/menu/joystickmenu.cpp | 1 + src/menu/loadsavemenu.cpp | 1 + src/menu/menu.cpp | 46 +- src/menu/menudef.cpp | 6 +- src/menu/messagebox.cpp | 3 +- src/menu/playermenu.cpp | 1 + src/menu/videomenu.cpp | 1 + src/p_acs.cpp | 16 +- src/p_actionfunctions.cpp | 4 +- src/p_ceiling.cpp | 1 + src/p_conversation.cpp | 4 +- src/p_effect.cpp | 1 + src/p_enemy.cpp | 4 +- src/p_floor.cpp | 1 + src/p_interaction.cpp | 16 +- src/p_linkedsectors.cpp | 1 + src/p_lnspec.cpp | 1 + src/p_map.cpp | 8 +- src/p_maputl.cpp | 1 + src/p_mobj.cpp | 41 +- src/p_pspr.cpp | 1 + src/p_sectors.cpp | 4 +- src/p_setup.cpp | 1 + src/p_sight.cpp | 1 + src/p_spec.cpp | 1 + src/p_states.cpp | 1 + src/p_tags.cpp | 1 + src/p_teleport.cpp | 1 + src/p_terrain.cpp | 1 + src/p_things.cpp | 1 + src/p_udmf.cpp | 1 + src/p_user.cpp | 12 +- src/portal.cpp | 1 + src/r_data/r_translate.cpp | 1 + src/r_data/sprites.cpp | 1 + src/s_sndseq.cpp | 1 + src/s_sound.cpp | 4 +- src/scripting/backend/codegen.cpp | 8 +- src/scripting/backend/codegen.h | 2 + src/scripting/backend/dynarrays.cpp | 4 +- src/scripting/backend/scopebarrier.cpp | 2 + src/scripting/backend/vmbuilder.cpp | 3 +- src/scripting/backend/vmbuilder.h | 1 + src/scripting/backend/vmdisasm.cpp | 1 + src/scripting/symbols.cpp | 76 + src/scripting/symbols.h | 3 +- src/scripting/thingdef.cpp | 2 +- src/scripting/thingdef.h | 1 + src/scripting/thingdef_data.cpp | 2 + src/scripting/thingdef_properties.cpp | 1 + src/scripting/types.cpp | 2689 +++++++++++++++++++++++ src/scripting/types.h | 641 ++++++ src/scripting/vm/vm.h | 495 +---- src/scripting/vm/vmexec.cpp | 4 + src/scripting/vm/vmexec.h | 10 - src/scripting/vm/vmframe.cpp | 52 +- src/scripting/vm/vmintern.h | 474 ++++ src/scripting/vm/vmops.h | 2 - src/scripting/zscript/ast.cpp | 2 + src/scripting/zscript/zcc_compile.cpp | 1 + src/scripting/zscript/zcc_parser.h | 3 +- src/sound/i_music.cpp | 1 + src/teaminfo.cpp | 1 + src/textures/texturemanager.cpp | 1 + src/v_draw.cpp | 1 + src/v_font.cpp | 1 + src/v_text.cpp | 1 + src/v_video.cpp | 1 + src/v_video.h | 1 + src/virtual.h | 30 - src/w_wad.cpp | 1 + src/wi_stuff.cpp | 8 +- 111 files changed, 4284 insertions(+), 4148 deletions(-) create mode 100644 src/scripting/types.cpp create mode 100644 src/scripting/types.h create mode 100644 src/scripting/vm/vmintern.h delete mode 100644 src/virtual.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dcabeb2a0..a6dcfd766 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1215,6 +1215,7 @@ set (PCH_SOURCES r_data/renderstyle.cpp r_data/r_interpolate.cpp scripting/symbols.cpp + scripting/types.cpp scripting/thingdef.cpp scripting/thingdef_data.cpp scripting/thingdef_properties.cpp diff --git a/src/am_map.cpp b/src/am_map.cpp index 31961831e..5c39857dc 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -734,8 +734,6 @@ static int grid = 0; bool automapactive = false; -DEFINE_GLOBAL(automapactive); - // location of window on screen static int f_x; static int f_y; diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 637494333..5fc891fb4 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -14,6 +14,7 @@ #include "d_net.h" #include "serializer.h" #include "d_player.h" +#include "vm.h" IMPLEMENT_CLASS(DBot, false, true) diff --git a/src/b_game.cpp b/src/b_game.cpp index 1c4230d56..ea80030ff 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -62,6 +62,7 @@ Everything that is changed is marked (maybe commented) with "Added by MC" #include "d_player.h" #include "doomerrors.h" #include "events.h" +#include "vm.h" static FRandom pr_botspawn ("BotSpawn"); diff --git a/src/c_bind.cpp b/src/c_bind.cpp index 540c77f7b..76c552db2 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -46,6 +46,7 @@ #include "w_wad.h" #include "templates.h" #include "dobject.h" +#include "vm.h" #include #include diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 4d40ce66d..b45210053 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1147,34 +1147,6 @@ CCMD(currentpos) } } -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- -CCMD(vmengine) -{ - if (argv.argc() == 2) - { - if (stricmp(argv[1], "default") == 0) - { - VMSelectEngine(VMEngine_Default); - return; - } - else if (stricmp(argv[1], "checked") == 0) - { - VMSelectEngine(VMEngine_Checked); - return; - } - else if (stricmp(argv[1], "unchecked") == 0) - { - VMSelectEngine(VMEngine_Unchecked); - return; - } - } - Printf("Usage: vmengine \n"); -} - //----------------------------------------------------------------------------- // // Print secret info (submitted by Karl Murks) diff --git a/src/c_console.cpp b/src/c_console.cpp index 0d37198f3..f401ed0e5 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -68,6 +68,7 @@ #include "gstrings.h" #include "c_consolebuffer.h" #include "g_levellocals.h" +#include "vm.h" FString FStringFormat(VM_ARGS); // extern from thingdef_data.cpp diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index f223444e4..6b0b62da7 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -52,6 +52,7 @@ #include "v_video.h" #include "colormatcher.h" #include "menu/menu.h" +#include "vm.h" struct FLatchedValue { diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index ad32fcca9..464ed4495 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -55,6 +55,7 @@ #include "d_main.h" #include "serializer.h" #include "menu/menu.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 2b7f6999a..dcb42a2bb 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -74,6 +74,7 @@ #include "info.h" #include "v_text.h" #include "backend/vmbuilder.h" +#include "types.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO diff --git a/src/d_main.cpp b/src/d_main.cpp index d6edd7230..b03ca3e50 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -112,6 +112,8 @@ #include "g_levellocals.h" #include "events.h" #include "r_utility.h" +#include "vm.h" +#include "types.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 74258e3ae..a476e4b8a 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -57,6 +57,7 @@ #include "templates.h" #include "cmdlib.h" #include "serializer.h" +#include "vm.h" static FRandom pr_pickteam ("PickRandomTeam"); diff --git a/src/dobject.cpp b/src/dobject.cpp index ca2a3e32f..687e76f85 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -48,8 +48,9 @@ #include "a_sharedglobal.h" #include "dsectoreffect.h" #include "serializer.h" -#include "virtual.h" +#include "vm.h" #include "g_levellocals.h" +#include "types.h" //========================================================================== // @@ -372,7 +373,7 @@ void DObject:: Destroy () IFVIRTUAL(DObject, OnDestroy) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0); + VMCall(func, params, 1, nullptr, 0); } } OnDestroy(); diff --git a/src/dobject.h b/src/dobject.h index 18a6f14b5..b4db0386a 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -247,13 +247,13 @@ public: void Destroy(); // Add other types as needed. - bool &BoolVar(FName field); - int &IntVar(FName field); - FSoundID &SoundVar(FName field); - PalEntry &ColorVar(FName field); - FName &NameVar(FName field); - double &FloatVar(FName field); - FString &StringVar(FName field); + inline bool &BoolVar(FName field); + inline int &IntVar(FName field); + inline FSoundID &SoundVar(FName field); + inline PalEntry &ColorVar(FName field); + inline FName &NameVar(FName field); + inline double &FloatVar(FName field); + inline FString &StringVar(FName field); template T*& PointerVar(FName field); // If you need to replace one object with another and want to @@ -409,4 +409,40 @@ template const T *dyn_cast(const DObject *p) return dyn_cast(const_cast(p)); } +inline bool &DObject::BoolVar(FName field) +{ + return *(bool*)ScriptVar(field, nullptr); +} + +inline int &DObject::IntVar(FName field) +{ + return *(int*)ScriptVar(field, nullptr); +} + +inline FSoundID &DObject::SoundVar(FName field) +{ + return *(FSoundID*)ScriptVar(field, nullptr); +} + +inline PalEntry &DObject::ColorVar(FName field) +{ + return *(PalEntry*)ScriptVar(field, nullptr); +} + +inline FName &DObject::NameVar(FName field) +{ + return *(FName*)ScriptVar(field, nullptr); +} + +inline double &DObject::FloatVar(FName field) +{ + return *(double*)ScriptVar(field, nullptr); +} + +template +inline T *&DObject::PointerVar(FName field) +{ + return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle. +} + #endif //__DOBJECT_H__ diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index a220e2df6..d7703de1c 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -49,6 +49,8 @@ #include "doomerrors.h" #include "fragglescript/t_fs.h" #include "a_keys.h" +#include "vm.h" +#include "types.h" // MACROS ------------------------------------------------------------------ @@ -66,36 +68,12 @@ EXTERN_CVAR(Bool, strictdecorate); // PUBLIC DATA DEFINITIONS ------------------------------------------------- FMemArena ClassDataAllocator(32768); // use this for all static class data that can be released in bulk when the type system is shut down. -FTypeTable TypeTable; TArray PClass::AllClasses; TMap PClass::ClassMap; TArray PClass::FunctionPtrList; bool PClass::bShutdown; bool PClass::bVMOperational; -PErrorType *TypeError; -PErrorType *TypeAuto; -PVoidType *TypeVoid; -PInt *TypeSInt8, *TypeUInt8; -PInt *TypeSInt16, *TypeUInt16; -PInt *TypeSInt32, *TypeUInt32; -PBool *TypeBool; -PFloat *TypeFloat32, *TypeFloat64; -PString *TypeString; -PName *TypeName; -PSound *TypeSound; -PColor *TypeColor; -PTextureID *TypeTextureID; -PSpriteID *TypeSpriteID; -PStatePointer *TypeState; -PPointer *TypeFont; -PStateLabel *TypeStateLabel; -PStruct *TypeVector2; -PStruct *TypeVector3; -PStruct *TypeColorStruct; -PStruct *TypeStringStruct; -PPointer *TypeNullPtr; -PPointer *TypeVoidPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -103,2572 +81,6 @@ PPointer *TypeVoidPtr; // A harmless non-nullptr FlatPointer for classes without pointers. static const size_t TheEnd = ~(size_t)0; -// CODE -------------------------------------------------------------------- - -IMPLEMENT_CLASS(PErrorType, false, false) -IMPLEMENT_CLASS(PVoidType, false, false) - -void DumpTypeTable() -{ - int used = 0; - int min = INT_MAX; - int max = 0; - int all = 0; - int lens[10] = {0}; - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - int len = 0; - Printf("%4zu:", i); - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) - { - Printf(" -> %s", ty->DescriptiveName()); - len++; - all++; - } - if (len != 0) - { - used++; - if (len < min) - min = len; - if (len > max) - max = len; - } - if (len < (int)countof(lens)) - { - lens[len]++; - } - Printf("\n"); - } - Printf("Used buckets: %d/%lu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); - Printf("Min bucket size: %d\n", min); - Printf("Max bucket size: %d\n", max); - Printf("Avg bucket size: %.2f\n", double(all) / used); - int j,k; - for (k = countof(lens)-1; k > 0; --k) - if (lens[k]) - break; - for (j = 0; j <= k; ++j) - Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); -} - -/* PType ******************************************************************/ - -IMPLEMENT_CLASS(PType, true, false) - -//========================================================================== -// -// PType Parameterized Constructor -// -//========================================================================== - -PType::PType(unsigned int size, unsigned int align) -: Size(size), Align(align), HashNext(nullptr) -{ - mDescriptiveName = "Type"; - loadOp = OP_NOP; - storeOp = OP_NOP; - moveOp = OP_NOP; - RegType = REGT_NIL; - RegCount = 1; -} - -//========================================================================== -// -// PType Destructor -// -//========================================================================== - -PType::~PType() -{ -} - -//========================================================================== -// -// PType :: WriteValue -// -//========================================================================== - -void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - assert(0 && "Cannot write value for this type"); -} - -//========================================================================== -// -// PType :: ReadValue -// -//========================================================================== - -bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - assert(0 && "Cannot read value for this type"); - return false; -} - -//========================================================================== -// -// PType :: SetDefaultValue -// -//========================================================================== - -void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) -{ -} - -//========================================================================== -// -// PType :: SetDefaultValue -// -//========================================================================== - -void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) -{ -} - -void PType::SetPointerArray(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 -// -//========================================================================== - -void PType::SetValue(void *addr, int val) -{ - assert(0 && "Cannot set int value for this type"); -} - -void PType::SetValue(void *addr, double val) -{ - assert(0 && "Cannot set float value for this type"); -} - -//========================================================================== -// -// PType :: GetValue -// -//========================================================================== - -int PType::GetValueInt(void *addr) const -{ - assert(0 && "Cannot get value for this type"); - return 0; -} - -double PType::GetValueFloat(void *addr) const -{ - assert(0 && "Cannot get value for this type"); - return 0; -} - -//========================================================================== -// -// PType :: IsMatch -// -//========================================================================== - -bool PType::IsMatch(intptr_t id1, intptr_t id2) const -{ - return false; -} - -//========================================================================== -// -// PType :: GetTypeIDs -// -//========================================================================== - -void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = 0; - id2 = 0; -} - -//========================================================================== -// -// PType :: GetTypeIDs -// -//========================================================================== - -const char *PType::DescriptiveName() const -{ - return mDescriptiveName.GetChars(); -} - -//========================================================================== -// -// PType :: StaticInit STATIC -// -//========================================================================== - -void PType::StaticInit() -{ - // Create types and add them type the type table. - TypeTable.AddType(TypeError = new PErrorType); - TypeTable.AddType(TypeAuto = new PErrorType(2)); - TypeTable.AddType(TypeVoid = new PVoidType); - TypeTable.AddType(TypeSInt8 = new PInt(1, false)); - TypeTable.AddType(TypeUInt8 = new PInt(1, true)); - TypeTable.AddType(TypeSInt16 = new PInt(2, false)); - TypeTable.AddType(TypeUInt16 = new PInt(2, true)); - TypeTable.AddType(TypeSInt32 = new PInt(4, false)); - TypeTable.AddType(TypeUInt32 = new PInt(4, true)); - TypeTable.AddType(TypeBool = new PBool); - TypeTable.AddType(TypeFloat32 = new PFloat(4)); - TypeTable.AddType(TypeFloat64 = new PFloat(8)); - TypeTable.AddType(TypeString = new PString); - TypeTable.AddType(TypeName = new PName); - TypeTable.AddType(TypeSound = new PSound); - TypeTable.AddType(TypeColor = new PColor); - TypeTable.AddType(TypeState = new PStatePointer); - TypeTable.AddType(TypeStateLabel = new PStateLabel); - TypeTable.AddType(TypeNullPtr = new PPointer); - TypeTable.AddType(TypeSpriteID = new PSpriteID); - TypeTable.AddType(TypeTextureID = new PTextureID); - - TypeVoidPtr = NewPointer(TypeVoid, false); - TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. - TypeStringStruct = NewStruct("Stringstruct", nullptr, true); - TypeFont = NewPointer(NewStruct("Font", nullptr, true)); -#ifdef __BIG_ENDIAN__ - TypeColorStruct->AddField(NAME_a, TypeUInt8); - TypeColorStruct->AddField(NAME_r, TypeUInt8); - TypeColorStruct->AddField(NAME_g, TypeUInt8); - TypeColorStruct->AddField(NAME_b, TypeUInt8); -#else - TypeColorStruct->AddField(NAME_b, TypeUInt8); - TypeColorStruct->AddField(NAME_g, TypeUInt8); - TypeColorStruct->AddField(NAME_r, TypeUInt8); - TypeColorStruct->AddField(NAME_a, TypeUInt8); -#endif - - TypeVector2 = new PStruct(NAME_Vector2, nullptr); - TypeVector2->AddField(NAME_X, TypeFloat64); - TypeVector2->AddField(NAME_Y, TypeFloat64); - TypeTable.AddType(TypeVector2); - TypeVector2->loadOp = OP_LV2; - TypeVector2->storeOp = OP_SV2; - TypeVector2->moveOp = OP_MOVEV2; - TypeVector2->RegType = REGT_FLOAT; - TypeVector2->RegCount = 2; - - TypeVector3 = new PStruct(NAME_Vector3, nullptr); - TypeVector3->AddField(NAME_X, TypeFloat64); - TypeVector3->AddField(NAME_Y, TypeFloat64); - TypeVector3->AddField(NAME_Z, TypeFloat64); - // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient - TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Transient, 0)); - TypeTable.AddType(TypeVector3); - TypeVector3->loadOp = OP_LV3; - TypeVector3->storeOp = OP_SV3; - TypeVector3->moveOp = OP_MOVEV3; - TypeVector3->RegType = REGT_FLOAT; - TypeVector3->RegCount = 3; - - - - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2)); - Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3)); -} - - -/* PBasicType *************************************************************/ - -IMPLEMENT_CLASS(PBasicType, true, false) - -//========================================================================== -// -// PBasicType Default Constructor -// -//========================================================================== - -PBasicType::PBasicType() -{ -} - -//========================================================================== -// -// PBasicType Parameterized Constructor -// -//========================================================================== - -PBasicType::PBasicType(unsigned int size, unsigned int align) -: PType(size, align) -{ - mDescriptiveName = "BasicType"; -} - -/* PCompoundType **********************************************************/ - -IMPLEMENT_CLASS(PCompoundType, true, false) - -/* PContainerType *************************************************************/ - -IMPLEMENT_CLASS(PContainerType, true, false) - -//========================================================================== -// -// PContainerType :: IsMatch -// -//========================================================================== - -bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const -{ - const DObject *outer = (const DObject *)id1; - FName name = (ENamedName)(intptr_t)id2; - - return Outer == outer && TypeName == name; -} - -//========================================================================== -// -// PContainerType :: GetTypeIDs -// -//========================================================================== - -void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)Outer; - id2 = TypeName; -} - -/* PInt *******************************************************************/ - -IMPLEMENT_CLASS(PInt, false, false) - -//========================================================================== -// -// PInt Default Constructor -// -//========================================================================== - -PInt::PInt() -: PBasicType(4, 4), Unsigned(false), IntCompatible(true) -{ - mDescriptiveName = "SInt32"; - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); - SetOps(); -} - -//========================================================================== -// -// PInt Parameterized Constructor -// -//========================================================================== - -PInt::PInt(unsigned int size, bool unsign, bool compatible) -: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) -{ - mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); - - MemberOnly = (size < 4); - if (!unsign) - { - int maxval = (1u << ((8 * size) - 1)) - 1; // compute as unsigned to prevent overflow before -1 - int minval = -maxval - 1; - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, minval)); - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, maxval)); - } - else - { - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); - Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << ((8 * size) - 1)))); - } - SetOps(); -} - -void PInt::SetOps() -{ - moveOp = OP_MOVE; - RegType = REGT_INT; - if (Size == 4) - { - storeOp = OP_SW; - loadOp = OP_LW; - } - else if (Size == 1) - { - storeOp = OP_SB; - loadOp = Unsigned ? OP_LBU : OP_LB; - } - else if (Size == 2) - { - storeOp = OP_SH; - loadOp = Unsigned ? OP_LHU : OP_LH; - } - else - { - assert(0 && "Unhandled integer size"); - storeOp = OP_NOP; - } -} - -//========================================================================== -// -// PInt :: WriteValue -// -//========================================================================== - -void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (Size == 8 && Unsigned) - { - // this is a special case that cannot be represented by an int64_t. - uint64_t val = *(uint64_t*)addr; - ar(key, val); - } - else - { - int64_t val; - switch (Size) - { - case 1: - val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr; - break; - - case 2: - val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr; - break; - - case 4: - val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr; - break; - - case 8: - val = *(int64_t*)addr; - break; - - default: - return; // something invalid - } - ar(key, val); - } -} - -//========================================================================== -// -// PInt :: ReadValue -// -//========================================================================== - -bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - NumericValue val; - - ar(key, val); - if (val.type == NumericValue::NM_invalid) return false; // not found or usable - if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval; - - // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both. - switch (Size) - { - case 1: - *(uint8_t*)addr = (uint8_t)val.signedval; - break; - - case 2: - *(uint16_t*)addr = (uint16_t)val.signedval; - break; - - case 4: - *(uint32_t*)addr = (uint32_t)val.signedval; - break; - - case 8: - *(uint64_t*)addr = (uint64_t)val.signedval; - break; - - default: - return false; // something invalid - } - - return true; -} - -//========================================================================== -// -// PInt :: SetValue -// -//========================================================================== - -void PInt::SetValue(void *addr, int val) -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - *(int *)addr = val; - } - else if (Size == 1) - { - *(uint8_t *)addr = val; - } - else if (Size == 2) - { - *(uint16_t *)addr = val; - } - else if (Size == 8) - { - *(uint64_t *)addr = val; - } - else - { - assert(0 && "Unhandled integer size"); - } -} - -void PInt::SetValue(void *addr, double val) -{ - SetValue(addr, (int)val); -} - -//========================================================================== -// -// PInt :: GetValueInt -// -//========================================================================== - -int PInt::GetValueInt(void *addr) const -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - return *(int *)addr; - } - else if (Size == 1) - { - return Unsigned ? *(uint8_t *)addr : *(int8_t *)addr; - } - else if (Size == 2) - { - return Unsigned ? *(uint16_t *)addr : *(int16_t *)addr; - } - else if (Size == 8) - { // truncated output - return (int)*(uint64_t *)addr; - } - else - { - assert(0 && "Unhandled integer size"); - return 0; - } -} - -//========================================================================== -// -// PInt :: GetValueFloat -// -//========================================================================== - -double PInt::GetValueFloat(void *addr) const -{ - return GetValueInt(addr); -} - -//========================================================================== -// -// PInt :: GetStoreOp -// -//========================================================================== - -/* PBool ******************************************************************/ - -IMPLEMENT_CLASS(PBool, false, false) - -//========================================================================== -// -// PInt :: SetValue -// -//========================================================================== - -void PBool::SetValue(void *addr, int val) -{ - *(bool*)addr = !!val; -} - -void PBool::SetValue(void *addr, double val) -{ - *(bool*)addr = val != 0.; -} - -int PBool::GetValueInt(void *addr) const -{ - return *(bool *)addr; -} - -double PBool::GetValueFloat(void *addr) const -{ - return *(bool *)addr; -} - -//========================================================================== -// -// PBool Default Constructor -// -//========================================================================== - -PBool::PBool() -: PInt(sizeof(bool), true) -{ - mDescriptiveName = "Bool"; - MemberOnly = false; -} - -/* PFloat *****************************************************************/ - -IMPLEMENT_CLASS(PFloat, false, false) - -//========================================================================== -// -// PFloat Default Constructor -// -//========================================================================== - -PFloat::PFloat() -: PBasicType(8, 8) -{ - mDescriptiveName = "Float"; - SetDoubleSymbols(); - SetOps(); -} - -//========================================================================== -// -// PFloat Parameterized Constructor -// -//========================================================================== - -PFloat::PFloat(unsigned int size) -: PBasicType(size, size) -{ - mDescriptiveName.Format("Float%d", size); - if (size == 8) - { -#ifdef __i386__ - // According to System V i386 ABI alignment of double type is 4 - // GCC and Clang for 32-bit Intel targets follow this requirement - // However GCC has -malign-double option to enable 8-byte alignment - // So calculation of the actual alignment is needed - struct AlignmentCheck { uint8_t i; double d; }; - Align = static_cast(offsetof(AlignmentCheck, d)); -#endif // __i386__ - - SetDoubleSymbols(); - } - else - { - assert(size == 4); - MemberOnly = true; - SetSingleSymbols(); - } - SetOps(); -} - -//========================================================================== -// -// PFloat :: SetDoubleSymbols -// -// Setup constant values for 64-bit floats. -// -//========================================================================== - -void PFloat::SetDoubleSymbols() -{ - static const SymbolInitF symf[] = - { - { NAME_Min_Normal, DBL_MIN }, - { NAME_Max, DBL_MAX }, - { NAME_Epsilon, DBL_EPSILON }, - { NAME_NaN, std::numeric_limits::quiet_NaN() }, - { NAME_Infinity, std::numeric_limits::infinity() }, - { NAME_Min_Denormal, std::numeric_limits::denorm_min() } - }; - static const SymbolInitI symi[] = - { - { NAME_Dig, DBL_DIG }, - { NAME_Min_Exp, DBL_MIN_EXP }, - { NAME_Max_Exp, DBL_MAX_EXP }, - { NAME_Mant_Dig, DBL_MANT_DIG }, - { NAME_Min_10_Exp, DBL_MIN_10_EXP }, - { NAME_Max_10_Exp, DBL_MAX_10_EXP } - }; - SetSymbols(symf, countof(symf)); - SetSymbols(symi, countof(symi)); -} - -//========================================================================== -// -// PFloat :: SetSingleSymbols -// -// Setup constant values for 32-bit floats. -// -//========================================================================== - -void PFloat::SetSingleSymbols() -{ - static const SymbolInitF symf[] = - { - { NAME_Min_Normal, FLT_MIN }, - { NAME_Max, FLT_MAX }, - { NAME_Epsilon, FLT_EPSILON }, - { NAME_NaN, std::numeric_limits::quiet_NaN() }, - { NAME_Infinity, std::numeric_limits::infinity() }, - { NAME_Min_Denormal, std::numeric_limits::denorm_min() } - }; - static const SymbolInitI symi[] = - { - { NAME_Dig, FLT_DIG }, - { NAME_Min_Exp, FLT_MIN_EXP }, - { NAME_Max_Exp, FLT_MAX_EXP }, - { NAME_Mant_Dig, FLT_MANT_DIG }, - { NAME_Min_10_Exp, FLT_MIN_10_EXP }, - { NAME_Max_10_Exp, FLT_MAX_10_EXP } - }; - SetSymbols(symf, countof(symf)); - SetSymbols(symi, countof(symi)); -} - -//========================================================================== -// -// PFloat :: SetSymbols -// -//========================================================================== - -void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) -{ - for (size_t i = 0; i < count; ++i) - { - Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); - } -} - -void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) -{ - for (size_t i = 0; i < count; ++i) - { - Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); - } -} - -//========================================================================== -// -// PFloat :: WriteValue -// -//========================================================================== - -void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (Size == 8) - { - ar(key, *(double*)addr); - } - else - { - ar(key, *(float*)addr); - } -} - -//========================================================================== -// -// PFloat :: ReadValue -// -//========================================================================== - -bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - NumericValue val; - - ar(key, val); - if (val.type == NumericValue::NM_invalid) return false; // not found or usable - else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval; - else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval; - - if (Size == 8) - { - *(double*)addr = val.floatval; - } - else - { - *(float*)addr = (float)val.floatval; - } - return true; -} - -//========================================================================== -// -// PFloat :: SetValue -// -//========================================================================== - -void PFloat::SetValue(void *addr, int val) -{ - return SetValue(addr, (double)val); -} - -void PFloat::SetValue(void *addr, double val) -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - *(float *)addr = (float)val; - } - else - { - assert(Size == 8); - *(double *)addr = val; - } -} - -//========================================================================== -// -// PFloat :: GetValueInt -// -//========================================================================== - -int PFloat::GetValueInt(void *addr) const -{ - return xs_ToInt(GetValueFloat(addr)); -} - -//========================================================================== -// -// PFloat :: GetValueFloat -// -//========================================================================== - -double PFloat::GetValueFloat(void *addr) const -{ - assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); - if (Size == 4) - { - return *(float *)addr; - } - else - { - assert(Size == 8); - return *(double *)addr; - } -} - -//========================================================================== -// -// PFloat :: GetStoreOp -// -//========================================================================== - -void PFloat::SetOps() -{ - if (Size == 4) - { - storeOp = OP_SSP; - loadOp = OP_LSP; - } - else - { - assert(Size == 8); - storeOp = OP_SDP; - loadOp = OP_LDP; - } - moveOp = OP_MOVEF; - RegType = REGT_FLOAT; -} - -/* PString ****************************************************************/ - -IMPLEMENT_CLASS(PString, false, false) - -//========================================================================== -// -// PString Default Constructor -// -//========================================================================== - -PString::PString() -: PBasicType(sizeof(FString), alignof(FString)) -{ - mDescriptiveName = "String"; - storeOp = OP_SS; - loadOp = OP_LS; - moveOp = OP_MOVES; - RegType = REGT_STRING; - -} - -//========================================================================== -// -// PString :: WriteValue -// -//========================================================================== - -void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - ar(key, *(FString*)addr); -} - -//========================================================================== -// -// PString :: ReadValue -// -//========================================================================== - -bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FString*)addr = cptr; - return true; - } -} - -//========================================================================== -// -// PString :: SetDefaultValue -// -//========================================================================== - -void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - if (base != nullptr) new((uint8_t *)base + offset) FString; - if (special != nullptr) - { - special->Push(std::make_pair(this, offset)); - } -} - -//========================================================================== -// -// PString :: InitializeValue -// -//========================================================================== - -void PString::InitializeValue(void *addr, const void *def) const -{ - if (def != nullptr) - { - new(addr) FString(*(FString *)def); - } - else - { - new(addr) FString; - } -} - -//========================================================================== -// -// PString :: DestroyValue -// -//========================================================================== - -void PString::DestroyValue(void *addr) const -{ - ((FString *)addr)->~FString(); -} - -/* PName ******************************************************************/ - -IMPLEMENT_CLASS(PName, false, false) - -//========================================================================== -// -// PName Default Constructor -// -//========================================================================== - -PName::PName() -: PInt(sizeof(FName), true, false) -{ - mDescriptiveName = "Name"; - assert(sizeof(FName) == alignof(FName)); -} - -//========================================================================== -// -// PName :: WriteValue -// -//========================================================================== - -void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - const char *cptr = ((const FName*)addr)->GetChars(); - ar.StringPtr(key, cptr); -} - -//========================================================================== -// -// PName :: ReadValue -// -//========================================================================== - -bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FName*)addr = FName(cptr); - return true; - } -} - -/* PSpriteID ******************************************************************/ - -IMPLEMENT_CLASS(PSpriteID, false, false) - -//========================================================================== -// -// PName Default Constructor -// -//========================================================================== - -PSpriteID::PSpriteID() - : PInt(sizeof(int), true, true) -{ - mDescriptiveName = "SpriteID"; -} - -//========================================================================== -// -// PName :: WriteValue -// -//========================================================================== - -void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - int32_t val = *(int*)addr; - ar.Sprite(key, val, nullptr); -} - -//========================================================================== -// -// PName :: ReadValue -// -//========================================================================== - -bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - int32_t val; - ar.Sprite(key, val, nullptr); - *(int*)addr = val; - return true; -} - -/* PTextureID ******************************************************************/ - -IMPLEMENT_CLASS(PTextureID, false, false) - -//========================================================================== -// -// PTextureID Default Constructor -// -//========================================================================== - -PTextureID::PTextureID() - : PInt(sizeof(FTextureID), true, false) -{ - mDescriptiveName = "TextureID"; - assert(sizeof(FTextureID) == alignof(FTextureID)); -} - -//========================================================================== -// -// PTextureID :: WriteValue -// -//========================================================================== - -void PTextureID::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - FTextureID val = *(FTextureID*)addr; - ar(key, val); -} - -//========================================================================== -// -// PTextureID :: ReadValue -// -//========================================================================== - -bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - FTextureID val; - ar(key, val); - *(FTextureID*)addr = val; - return true; -} - -/* PSound *****************************************************************/ - -IMPLEMENT_CLASS(PSound, false, false) - -//========================================================================== -// -// PSound Default Constructor -// -//========================================================================== - -PSound::PSound() -: PInt(sizeof(FSoundID), true) -{ - mDescriptiveName = "Sound"; - assert(sizeof(FSoundID) == alignof(FSoundID)); -} - -//========================================================================== -// -// PSound :: WriteValue -// -//========================================================================== - -void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - const char *cptr = *(const FSoundID *)addr; - ar.StringPtr(key, cptr); -} - -//========================================================================== -// -// PSound :: ReadValue -// -//========================================================================== - -bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - const char *cptr; - ar.StringPtr(key, cptr); - if (cptr == nullptr) - { - return false; - } - else - { - *(FSoundID *)addr = FSoundID(cptr); - return true; - } -} - -/* PColor *****************************************************************/ - -IMPLEMENT_CLASS(PColor, false, false) - -//========================================================================== -// -// PColor Default Constructor -// -//========================================================================== - -PColor::PColor() -: PInt(sizeof(PalEntry), true) -{ - mDescriptiveName = "Color"; - assert(sizeof(PalEntry) == alignof(PalEntry)); -} - -/* PStateLabel *****************************************************************/ - -IMPLEMENT_CLASS(PStateLabel, false, false) - -//========================================================================== -// -// PStateLabel Default Constructor -// -//========================================================================== - -PStateLabel::PStateLabel() - : PInt(sizeof(int), false, false) -{ - mDescriptiveName = "StateLabel"; -} - -/* PPointer ***************************************************************/ - -IMPLEMENT_CLASS(PPointer, false, false) - -//========================================================================== -// -// PPointer - Default Constructor -// -//========================================================================== - -PPointer::PPointer() -: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) -{ - mDescriptiveName = "NullPointer"; - loadOp = OP_LP; - storeOp = OP_SP; - moveOp = OP_MOVEA; - RegType = REGT_POINTER; -} - -//========================================================================== -// -// PPointer - Parameterized Constructor -// -//========================================================================== - -PPointer::PPointer(PType *pointsat, bool isconst) -: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) -{ - if (pointsat != nullptr) - { - mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); - mVersion = pointsat->mVersion; - } - else - { - mDescriptiveName = "Pointer"; - mVersion = 0; - } - loadOp = OP_LP; - storeOp = OP_SP; - moveOp = OP_MOVEA; - RegType = REGT_POINTER; -} - -//========================================================================== -// -// PPointer :: IsMatch -// -//========================================================================== - -bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const -{ - assert(id2 == 0 || id2 == 1); - PType *pointat = (PType *)id1; - - return pointat == PointedType && (!!id2) == IsConst; -} - -//========================================================================== -// -// PPointer :: GetTypeIDs -// -//========================================================================== - -void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)PointedType; - id2 = 0; -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (writer != nullptr) - { - writer(ar, key, addr); - } - else - { - I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); - } -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (reader != nullptr) - { - return reader(ar, key, addr); - } - return false; -} - -/* PObjectPointer **********************************************************/ - -IMPLEMENT_CLASS(PObjectPointer, false, false) - -//========================================================================== -// -// PPointer :: GetStoreOp -// -//========================================================================== - -PObjectPointer::PObjectPointer(PClass *cls, bool isconst) - : PPointer(cls->VMType, isconst) -{ - loadOp = OP_LO; - // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. - if (cls && !cls->IsDescendantOf(RUNTIME_CLASS(DThinker))) storeOp = OP_SO; -} - -//========================================================================== -// -// PPointer :: SetPointer -// -//========================================================================== - -void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) -{ - // Add to the list of pointers for this class. - special->Push(offset); -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PObjectPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(DObject **)addr); -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - bool res; - ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); - return res; -} - -//========================================================================== -// -// NewPointer -// -// Returns a PPointer to an object of the specified type -// -//========================================================================== - -PPointer *NewPointer(PType *type, bool isconst) -{ - auto cp = dyn_cast(type); - if (cp) return NewPointer(cp->Descriptor, isconst); - - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PPointer(type, isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); -} - -PPointer *NewPointer(PClass *cls, bool isconst) -{ - assert(cls->VMType != nullptr); - - auto type = cls->VMType; - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); - if (ptype == nullptr) - { - ptype = new PObjectPointer(cls, isconst); - TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); - } - return static_cast(ptype); -} - -/* PStatePointer **********************************************************/ - -IMPLEMENT_CLASS(PStatePointer, false, false) - -//========================================================================== -// -// PStatePointer Default Constructor -// -//========================================================================== - -PStatePointer::PStatePointer() -{ - mDescriptiveName = "Pointer"; - PointedType = NewStruct(NAME_State, nullptr, true); - IsConst = true; -} - -//========================================================================== -// -// PStatePointer :: WriteValue -// -//========================================================================== - -void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(FState **)addr); -} - -//========================================================================== -// -// PStatePointer :: ReadValue -// -//========================================================================== - -bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - bool res = false; - ::Serialize(ar, key, *(FState **)addr, nullptr, &res); - return res; -} - - - -/* PClassPointer **********************************************************/ - -IMPLEMENT_CLASS(PClassPointer,false, false) - -//========================================================================== -// -// PClassPointer - Parameterized Constructor -// -//========================================================================== - -PClassPointer::PClassPointer(PClass *restrict) -: PPointer(restrict->VMType), ClassRestriction(restrict) -{ - if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); - else mDescriptiveName = "ClassPointer"; - loadOp = OP_LP; - storeOp = OP_SP; - mVersion = restrict->VMType->mVersion; -} - -//========================================================================== -// -// PPointer :: WriteValue -// -//========================================================================== - -void PClassPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const -{ - ar(key, *(PClass **)addr); -} - -//========================================================================== -// -// PPointer :: ReadValue -// -//========================================================================== - -bool PClassPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); - return false; -} - -//========================================================================== -// -// PClassPointer - isCompatible -// -//========================================================================== - -bool PClassPointer::isCompatible(PType *type) -{ - auto other = dyn_cast(type); - return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction)); -} - -//========================================================================== -// -// PClassPointer :: SetPointer -// -//========================================================================== - -void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) -{ -} - -//========================================================================== -// -// PClassPointer :: IsMatch -// -//========================================================================== - -bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PClass *classat = (const PClass *)id2; - return classat == ClassRestriction; -} - -//========================================================================== -// -// PClassPointer :: GetTypeIDs -// -//========================================================================== - -void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = 0; - id2 = (intptr_t)ClassRestriction; -} - -//========================================================================== -// -// NewClassPointer -// -// Returns a PClassPointer for the restricted type. -// -//========================================================================== - -PClassPointer *NewClassPointer(PClass *restrict) -{ - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, &bucket); - if (ptype == nullptr) - { - ptype = new PClassPointer(restrict); - TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, bucket); - } - return static_cast(ptype); -} - -/* PEnum ******************************************************************/ - -IMPLEMENT_CLASS(PEnum, false, false) - -//========================================================================== -// -// PEnum - Default Constructor -// -//========================================================================== - -PEnum::PEnum() -: PInt(4, false) -{ - mDescriptiveName = "Enum"; -} - -//========================================================================== -// -// PEnum - Parameterized Constructor -// -//========================================================================== - -PEnum::PEnum(FName name, PTypeBase *outer) -: PInt(4, false) -{ - EnumName = name; - Outer = outer; - mDescriptiveName.Format("Enum<%s>", name.GetChars()); -} - -//========================================================================== -// -// NewEnum -// -// Returns a PEnum for the given name and container, making sure not to -// create duplicates. -// -//========================================================================== - -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 == nullptr) - { - etype = new PEnum(name, outer); - TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); - } - return static_cast(etype); -} - -/* PArray *****************************************************************/ - -IMPLEMENT_CLASS(PArray, false, false) - -//========================================================================== -// -// PArray - Default Constructor -// -//========================================================================== - -PArray::PArray() -: ElementType(nullptr), ElementCount(0) -{ - mDescriptiveName = "Array"; -} - -//========================================================================== -// -// PArray - Parameterized Constructor -// -//========================================================================== - -PArray::PArray(PType *etype, unsigned int ecount) -: ElementType(etype), ElementCount(ecount) -{ - mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); - - Align = etype->Align; - // Since we are concatenating elements together, the element size should - // also be padded to the nearest alignment. - ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); - Size = ElementSize * ecount; -} - -//========================================================================== -// -// PArray :: IsMatch -// -//========================================================================== - -bool PArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *elemtype = (const PType *)id1; - unsigned int count = (unsigned int)(intptr_t)id2; - - return elemtype == ElementType && count == ElementCount; -} - -//========================================================================== -// -// PArray :: GetTypeIDs -// -//========================================================================== - -void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - id2 = ElementCount; -} - -//========================================================================== -// -// PArray :: WriteValue -// -//========================================================================== - -void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginArray(key)) - { - const uint8_t *addrb = (const uint8_t *)addr; - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->WriteValue(ar, nullptr, addrb); - addrb += ElementSize; - } - ar.EndArray(); - } -} - -//========================================================================== -// -// PArray :: ReadValue -// -//========================================================================== - -bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginArray(key)) - { - bool readsomething = false; - unsigned count = ar.ArraySize(); - unsigned loop = MIN(count, ElementCount); - uint8_t *addrb = (uint8_t *)addr; - for(unsigned i=0;iReadValue(ar, nullptr, addrb); - addrb += ElementSize; - } - if (loop < count) - { - DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", - count, ElementCount); - } - ar.EndArray(); - return readsomething; - } - return false; -} - -//========================================================================== -// -// PArray :: SetDefaultValue -// -//========================================================================== - -void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->SetDefaultValue(base, offset + i*ElementSize, special); - } -} - -//========================================================================== -// -// PArray :: SetDefaultValue -// -//========================================================================== - -void PArray::SetPointer(void *base, unsigned offset, TArray *special) -{ - for (unsigned i = 0; i < ElementCount; ++i) - { - ElementType->SetPointer(base, offset + i*ElementSize, special); - } -} - -//========================================================================== -// -// NewArray -// -// Returns a PArray for the given type and size, making sure not to create -// duplicates. -// -//========================================================================== - -PArray *NewArray(PType *type, unsigned int count) -{ - size_t bucket; - PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); - if (atype == nullptr) - { - atype = new PArray(type, count); - TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); - } - return (PArray *)atype; -} - -/* PArray *****************************************************************/ - -IMPLEMENT_CLASS(PStaticArray, false, false) - -//========================================================================== -// -// PArray - Default Constructor -// -//========================================================================== - -PStaticArray::PStaticArray() -{ - mDescriptiveName = "ResizableArray"; -} - -//========================================================================== -// -// PArray - Parameterized Constructor -// -//========================================================================== - -PStaticArray::PStaticArray(PType *etype) - : PArray(etype, 0) -{ - mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName()); -} - -//========================================================================== -// -// PArray :: IsMatch -// -//========================================================================== - -bool PStaticArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *elemtype = (const PType *)id1; - unsigned int count = (unsigned int)(intptr_t)id2; - - return elemtype == ElementType && count == 0; -} - -//========================================================================== -// -// PArray :: GetTypeIDs -// -//========================================================================== - -void PStaticArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - id2 = 0; -} - -//========================================================================== -// -// NewStaticArray -// -// Returns a PArray for the given type and size, making sure not to create -// duplicates. -// -//========================================================================== - -PStaticArray *NewStaticArray(PType *type) -{ - size_t bucket; - PType *atype = TypeTable.FindType(RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, &bucket); - if (atype == nullptr) - { - atype = new PStaticArray(type); - TypeTable.AddType(atype, RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, bucket); - } - return (PStaticArray *)atype; -} - -/* PDynArray **************************************************************/ - -IMPLEMENT_CLASS(PDynArray, false, false) - -//========================================================================== -// -// PDynArray - Default Constructor -// -//========================================================================== - -PDynArray::PDynArray() -: ElementType(nullptr) -{ - mDescriptiveName = "DynArray"; - Size = sizeof(FArray); - Align = alignof(FArray); -} - -//========================================================================== -// -// PDynArray - Parameterized Constructor -// -//========================================================================== - -PDynArray::PDynArray(PType *etype,PStruct *backing) -: ElementType(etype), BackingType(backing) -{ - mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); - Size = sizeof(FArray); - Align = alignof(FArray); -} - -//========================================================================== -// -// PDynArray :: IsMatch -// -//========================================================================== - -bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const -{ - assert(id2 == 0); - const PType *elemtype = (const PType *)id1; - - return elemtype == ElementType; -} - -//========================================================================== -// -// PDynArray :: GetTypeIDs -// -//========================================================================== - -void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)ElementType; - 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) -{ - if (base != nullptr) 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(PObjectPointer))) - { - // 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 uint8_t *addrb = (const uint8_t *)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; - - uint8_t *addrb = (uint8_t *)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 -// -// Creates a new DynArray of the given type, making sure not to create a -// duplicate. -// -//========================================================================== - -PDynArray *NewDynArray(PType *type) -{ - size_t bucket; - PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); - if (atype == nullptr) - { - FString backingname; - - switch (type->GetRegType()) - { - case REGT_INT: - backingname.Format("DynArray_I%d", type->Size * 8); - break; - - case REGT_FLOAT: - backingname.Format("DynArray_F%d", type->Size * 8); - break; - - case REGT_STRING: - backingname = "DynArray_String"; - break; - - case REGT_POINTER: - backingname = "DynArray_Ptr"; - break; - - default: - I_Error("Unsupported dynamic array requested"); - break; - } - - auto backing = NewStruct(backingname, nullptr, true); - atype = new PDynArray(type, backing); - TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); - } - return (PDynArray *)atype; -} - -/* PMap *******************************************************************/ - -IMPLEMENT_CLASS(PMap, false, false) - -//========================================================================== -// -// PMap - Default Constructor -// -//========================================================================== - -PMap::PMap() -: KeyType(nullptr), ValueType(nullptr) -{ - mDescriptiveName = "Map"; - Size = sizeof(FMap); - Align = alignof(FMap); -} - -//========================================================================== -// -// PMap - Parameterized Constructor -// -//========================================================================== - -PMap::PMap(PType *keytype, PType *valtype) -: KeyType(keytype), ValueType(valtype) -{ - mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); - Size = sizeof(FMap); - Align = alignof(FMap); -} - -//========================================================================== -// -// PMap :: IsMatch -// -//========================================================================== - -bool PMap::IsMatch(intptr_t id1, intptr_t id2) const -{ - const PType *keyty = (const PType *)id1; - const PType *valty = (const PType *)id2; - - return keyty == KeyType && valty == ValueType; -} - -//========================================================================== -// -// PMap :: GetTypeIDs -// -//========================================================================== - -void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)KeyType; - id2 = (intptr_t)ValueType; -} - -//========================================================================== -// -// NewMap -// -// Returns a PMap for the given key and value types, ensuring not to create -// duplicates. -// -//========================================================================== - -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 == nullptr) - { - maptype = new PMap(keytype, valuetype); - TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); - } - return (PMap *)maptype; -} - -/* PStruct ****************************************************************/ - -IMPLEMENT_CLASS(PStruct, false, false) - -//========================================================================== -// -// PStruct - Default Constructor -// -//========================================================================== - -PStruct::PStruct() -{ - mDescriptiveName = "Struct"; - Size = 0; -} - -//========================================================================== -// -// PStruct - Parameterized Constructor -// -//========================================================================== - -PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) -: PContainerType(name, outer) -{ - mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); - Size = 0; - isNative = isnative; -} - -//========================================================================== -// -// PStruct :: SetDefaultValue -// -//========================================================================== - -void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) -{ - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field && !(field->Flags & VARF_Transient)) - { - field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); - } - } -} - -//========================================================================== -// -// PStruct :: SetPointer -// -//========================================================================== - -void PStruct::SetPointer(void *base, unsigned offset, TArray *special) -{ - auto it = Symbols.GetIterator(); - PSymbolTable::MapType::Pair *pair; - while (it.NextPair(pair)) - { - auto field = dyn_cast(pair->Value); - if (field && !(field->Flags & VARF_Transient)) - { - field->Type->SetPointer(base, unsigned(offset + field->Offset), special); - } - } -} - -//========================================================================== -// -// PStruct :: WriteValue -// -//========================================================================== - -void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) const -{ - if (ar.BeginObject(key)) - { - Symbols.WriteFields(ar, addr); - ar.EndObject(); - } -} - -//========================================================================== -// -// PStruct :: ReadValue -// -//========================================================================== - -bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const -{ - if (ar.BeginObject(key)) - { - bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); - ar.EndObject(); - return ret; - } - return false; -} - -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new field to the end of a struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PStruct::AddField(FName name, PType *type, uint32_t flags) -{ - return Symbols.AddField(name, type, flags, Size, &Align); -} - -//========================================================================== -// -// PStruct :: AddField -// -// Appends a new native field to the struct. Returns either the new field -// or nullptr if a symbol by that name already exists. -// -//========================================================================== - -PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - return Symbols.AddNativeField(name, type, address, flags, bitvalue); -} - -//========================================================================== -// -// NewStruct -// Returns a PStruct for the given name and container, making sure not to -// create duplicates. -// -//========================================================================== - -PStruct *NewStruct(FName name, PTypeBase *outer, bool native) -{ - 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 == nullptr) - { - stype = new PStruct(name, outer, native); - TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); - } - return static_cast(stype); -} - - -/* PField *****************************************************************/ - -IMPLEMENT_CLASS(PField, false, false) - -//========================================================================== -// -// PField - Default Constructor -// -//========================================================================== - -PField::PField() -: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) -{ -} - - -PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitvalue) - : PSymbol(name), Offset(offset), Type(type), Flags(flags) -{ - if (bitvalue != 0) - { - BitValue = 0; - unsigned val = bitvalue; - while ((val >>= 1)) BitValue++; - - if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size) - { - // map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values. -#ifndef __BIG_ENDIAN__ - Offset += BitValue / 8; -#else - Offset += type->Size - 1 - BitValue / 8; -#endif - BitValue &= 7; - Type = TypeBool; - } - else - { - // Just abort. Bit fields should only be defined internally. - I_Error("Trying to create an invalid bit field element: %s", name.GetChars()); - } - } - else BitValue = -1; -} - -VersionInfo PField::GetVersion() -{ - VersionInfo Highest = { 0,0,0 }; - if (!(Flags & VARF_Deprecated)) Highest = mVersion; - if (Type->mVersion > Highest) Highest = Type->mVersion; - return Highest; -} - -/* PProperty *****************************************************************/ - -IMPLEMENT_CLASS(PProperty, false, false) - -//========================================================================== -// -// PField - Default Constructor -// -//========================================================================== - -PProperty::PProperty() - : PSymbol(NAME_None) -{ -} - -PProperty::PProperty(FName name, TArray &fields) - : PSymbol(name) -{ - Variables = std::move(fields); -} - -/* PPrototype *************************************************************/ - -IMPLEMENT_CLASS(PPrototype, false, false) - -//========================================================================== -// -// PPrototype - Default Constructor -// -//========================================================================== - -PPrototype::PPrototype() -{ -} - -//========================================================================== -// -// PPrototype - Parameterized Constructor -// -//========================================================================== - -PPrototype::PPrototype(const TArray &rettypes, const TArray &argtypes) -: ArgumentTypes(argtypes), ReturnTypes(rettypes) -{ -} - -//========================================================================== -// -// PPrototype :: IsMatch -// -//========================================================================== - -bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const -{ - const TArray *args = (const TArray *)id1; - const TArray *rets = (const TArray *)id2; - - return *args == ArgumentTypes && *rets == ReturnTypes; -} - -//========================================================================== -// -// PPrototype :: GetTypeIDs -// -//========================================================================== - -void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const -{ - id1 = (intptr_t)&ArgumentTypes; - id2 = (intptr_t)&ReturnTypes; -} - -//========================================================================== -// -// PPrototype :: PropagateMark -// -//========================================================================== - -size_t PPrototype::PropagateMark() -{ - GC::MarkArray(ArgumentTypes); - GC::MarkArray(ReturnTypes); - return (ArgumentTypes.Size() + ReturnTypes.Size()) * sizeof(void*) + - Super::PropagateMark(); -} - -//========================================================================== -// -// NewPrototype -// -// Returns a PPrototype for the given return and argument types, making sure -// not to create duplicates. -// -//========================================================================== - -PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes) -{ - size_t bucket; - PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); - if (proto == nullptr) - { - proto = new PPrototype(rettypes, argtypes); - TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); - } - return static_cast(proto); -} - -/* PClass *****************************************************************/ - -IMPLEMENT_CLASS(PClassType, false, false) - -//========================================================================== -// -// -// -//========================================================================== - -PClassType::PClassType(PClass *cls) -{ - assert(cls->VMType == nullptr); - Descriptor = cls; - TypeName = cls->TypeName; - if (cls->ParentClass != nullptr) - { - ParentType = cls->ParentClass->VMType; - assert(ParentType != nullptr); - Symbols.SetParentTable(&ParentType->Symbols); - } - cls->VMType = this; - mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); -} - -//========================================================================== -// -// PClass :: AddField -// -//========================================================================== - -PField *PClassType::AddField(FName name, PType *type, uint32_t flags) -{ - return Descriptor->AddField(name, type, flags); -} - -//========================================================================== -// -// PClass :: AddNativeField -// -//========================================================================== - -PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) -{ - auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); - if (field != nullptr) Descriptor->Fields.Push(field); - return field; -} - -//========================================================================== -// -// -// -//========================================================================== - -PClassType *NewClassType(PClass *cls) -{ - size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, &bucket); - if (ptype == nullptr) - { - ptype = new PClassType(cls); - TypeTable.AddType(ptype, RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, bucket); - } - return static_cast(ptype); -} - - //========================================================================== // // PClass :: WriteValue @@ -3215,10 +627,6 @@ void PClass::InitializeDefaults() } } } - else - { - Printf("VM-less class %s\n", TypeName.GetChars()); - } } //========================================================================== @@ -3586,133 +994,12 @@ void PClass::FindFunction(VMFunction **pptr, FName clsname, FName funcname) FunctionPtrList.Push(pptr); } - -/* FTypeTable **************************************************************/ - -//========================================================================== -// -// FTypeTable :: FindType -// -//========================================================================== - -PType *FTypeTable::FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum) +unsigned GetVirtualIndex(PClass *cls, const char *funcname) { - size_t bucket = Hash(metatype, parm1, parm2) % HASH_SIZE; - if (bucketnum != nullptr) - { - *bucketnum = bucket; - } - for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) - { - if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) - { - return type; - } - } - return nullptr; -} - -//========================================================================== -// -// FTypeTable :: AddType - Fully Parameterized Version -// -//========================================================================== - -void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket) -{ -#ifdef _DEBUG - size_t bucketcheck; - 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; - type->Release(); -} - -//========================================================================== -// -// FTypeTable :: AddType - Simple Version -// -//========================================================================== - -void FTypeTable::AddType(PType *type) -{ - intptr_t parm1, parm2; - size_t bucket; - - // 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"); - - type->HashNext = TypeHash[bucket]; - TypeHash[bucket] = type; - type->Release(); -} - -//========================================================================== -// -// FTypeTable :: Hash STATIC -// -//========================================================================== - -size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) -{ - size_t i1 = (size_t)p1; - - // Swap the high and low halves of i1. The compiler should be smart enough - // to transform this into a ROR or ROL. - i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); - - if (p1 != RUNTIME_CLASS(PPrototype)) - { - size_t i2 = (size_t)p2; - size_t i3 = (size_t)p3; - return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime - } - else - { // Prototypes need to hash the TArrays at p2 and p3 - const TArray *a2 = (const TArray *)p2; - const TArray *a3 = (const TArray *)p3; - for (unsigned i = 0; i < a2->Size(); ++i) - { - i1 = (i1 * 961748927) + (size_t)((*a2)[i]); - } - for (unsigned i = 0; i < a3->Size(); ++i) - { - i1 = (i1 * 961748927) + (size_t)((*a3)[i]); - } - return i1; - } -} - -//========================================================================== -// -// FTypeTable :: Clear -// -//========================================================================== - -void FTypeTable::Clear() -{ - for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) - { - for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) - { - auto next = ty->HashNext; - delete ty; - ty = next; - } - } - memset(TypeHash, 0, sizeof(TypeHash)); -} - -#include "c_dispatch.h" -CCMD(typetable) -{ - DumpTypeTable(); + // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. + auto sym = dyn_cast(cls->FindSymbol(funcname, false)); + assert(sym != nullptr); + auto VIndex = sym->Variants[0].Implementation->VirtualIndex; + return VIndex; } diff --git a/src/dobjtype.h b/src/dobjtype.h index dfb362a81..24cd43451 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -5,50 +5,17 @@ #error You must #include "dobject.h" to get dobjtype.h #endif -typedef std::pair FTypeAndOffset; -class PStruct; +#include "memarena.h" +typedef std::pair FTypeAndOffset; + +#if 0 // This is intentionally not in vm.h so that this file remains free of DObject pollution. class VMException : public DObject { DECLARE_CLASS(VMException, DObject); }; - - -#include "vm.h" - -// Variable/parameter/field flags ------------------------------------------- - -// Making all these different storage types use a common set of flags seems -// like the simplest thing to do. - -enum -{ - VARF_Optional = (1<<0), // func param is optional - VARF_Method = (1<<1), // func has an implied self parameter - VARF_Action = (1<<2), // func has implied owner and state parameters - VARF_Native = (1<<3), // func is native code, field is natively defined - VARF_ReadOnly = (1<<4), // field is read only, do not write to it - VARF_Private = (1<<5), // field is private to containing class - VARF_Protected = (1<<6), // field is only accessible by containing class and children. - VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used. - VARF_Virtual = (1<<8), // function is virtual - VARF_Final = (1<<9), // Function may not be overridden in subclasses - VARF_In = (1<<10), - VARF_Out = (1<<11), - VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) - VARF_Static = (1<<13), - VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. - VARF_Override = (1<<15), // overrides a virtual function from the parent class. - VARF_Ref = (1<<16), // argument is passed by reference. - VARF_Transient = (1<<17), // don't auto serialize field. - VARF_Meta = (1<<18), // static class data (by necessity read only.) - VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature - VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim) - VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui) - VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only) - VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data. -}; +#endif // An action function ------------------------------------------------------- @@ -58,549 +25,16 @@ class VMFrameStack; struct VMValue; struct VMReturn; class VMFunction; +class PClassType; struct FNamespaceManager; -// Basic information shared by all types ------------------------------------ - -// Only one copy of a type is ever instantiated at one time. -// - Enums, classes, and structs are defined by their names and outer classes. -// - Pointers are uniquely defined by the type they point at. -// - ClassPointers are also defined by their class restriction. -// - Arrays are defined by their element type and count. -// - DynArrays are defined by their element type. -// - Maps are defined by their key and value types. -// - Prototypes are defined by the argument and return types. -// - Functions are defined by their names and outer objects. -// In table form: -// Outer Name Type Type2 Count -// Enum * * -// Class * * -// Struct * * -// Function * * -// Pointer * -// ClassPointer + * -// Array * * -// DynArray * -// Map * * -// Prototype *+ *+ - -struct ZCC_ExprConstant; -class PType : public PTypeBase -{ - DECLARE_ABSTRACT_CLASS(PType, PTypeBase) -protected: - -public: - 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 - PSymbolTable Symbols; - bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument. - FString mDescriptiveName; - VersionInfo mVersion = { 0,0,0 }; - uint8_t loadOp, storeOp, moveOp, RegType, RegCount; - - PType(unsigned int size = 1, unsigned int align = 1); - virtual ~PType(); - virtual bool isNumeric() { return false; } - - // Writes the value of a variable of this type at (addr) to an archive, preceded by - // a tag indicating its type. The tag is there so that variable types can be changed - // without completely breaking savegames, provided that the change isn't between - // totally unrelated types. - virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const; - - // Returns true if the stored value was compatible. False otherwise. - // If the value was incompatible, then the memory at *addr is unchanged. - virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const; - - // 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); - virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL); - 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; - - // 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); - - // Gets the value of a variable of this type at (addr) - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - - // Gets the opcode to store from a register to memory - int GetStoreOp() const - { - return storeOp; - } - - // Gets the opcode to load from memory to a register - int GetLoadOp() const - { - return loadOp; - } - - // Gets the opcode to move from register to another register - int GetMoveOp() const - { - return moveOp; - } - - // Gets the register type for this type - int GetRegType() const - { - return RegType; - } - - int GetRegCount() const - { - return RegCount; - } - // Returns true if this type matches the two identifiers. Referring to the - // above table, any type is identified by at most two characteristics. Each - // type that implements this function will cast these to the appropriate type. - // It is up to the caller to make sure they are the correct types. There is - // only one prototype for this function in order to simplify type table - // management. - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - - // Get the type IDs used by IsMatch - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - - const char *DescriptiveName() const; - - static void StaticInit(); -}; - -// Not-really-a-type types -------------------------------------------------- - -class PErrorType : public PType -{ - DECLARE_CLASS(PErrorType, PType); -public: - PErrorType(int which = 1) : PType(0, which) {} -}; - -class PVoidType : public PType -{ - DECLARE_CLASS(PVoidType, PType); -public: - PVoidType() : PType(0, 1) {} -}; - -// Some categorization typing ----------------------------------------------- - -class PBasicType : public PType -{ - DECLARE_ABSTRACT_CLASS(PBasicType, PType); -public: - PBasicType(); - PBasicType(unsigned int size, unsigned int align); -}; - -class PCompoundType : public PType -{ - DECLARE_ABSTRACT_CLASS(PCompoundType, PType); -}; - -class PContainerType : public PCompoundType -{ - DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType); -public: - PTypeBase *Outer; // object this type is contained within - FName TypeName; // this type's name - - PContainerType() : Outer(NULL) { - mDescriptiveName = "NamedType"; - } - PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { - mDescriptiveName = name.GetChars(); - } - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; - virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; -}; - -// Basic types -------------------------------------------------------------- - -class PInt : public PBasicType -{ - DECLARE_CLASS(PInt, PBasicType); -public: - PInt(unsigned int size, bool unsign, bool compatible = true); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - virtual bool isNumeric() override { return IntCompatible; } - - bool Unsigned; - bool IntCompatible; -protected: - PInt(); - void SetOps(); -}; - -class PBool : public PInt -{ - DECLARE_CLASS(PBool, PInt); -public: - PBool(); - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; -}; - -class PFloat : public PBasicType -{ - DECLARE_CLASS(PFloat, PBasicType); -public: - PFloat(unsigned int size); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; - - virtual void SetValue(void *addr, int val); - virtual void SetValue(void *addr, double val); - virtual int GetValueInt(void *addr) const; - virtual double GetValueFloat(void *addr) const; - virtual bool isNumeric() override { return true; } -protected: - PFloat(); - void SetOps(); -private: - struct SymbolInitF - { - ENamedName Name; - double Value; - }; - struct SymbolInitI - { - ENamedName Name; - int Value; - }; - - void SetSingleSymbols(); - void SetDoubleSymbols(); - void SetSymbols(const SymbolInitF *syminit, size_t count); - void SetSymbols(const SymbolInitI *syminit, size_t count); -}; - -class PString : public PBasicType -{ - DECLARE_CLASS(PString, PBasicType); -public: - PString(); - - 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 *special=NULL) override; - void InitializeValue(void *addr, const void *def) const override; - void DestroyValue(void *addr) const override; -}; - -// Variations of integer types ---------------------------------------------- - -class PName : public PInt -{ - DECLARE_CLASS(PName, PInt); -public: - PName(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; -}; - -class PSound : public PInt -{ - DECLARE_CLASS(PSound, PInt); -public: - PSound(); - - void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; -}; - -class PSpriteID : public PInt -{ - DECLARE_CLASS(PSpriteID, PInt); -public: - PSpriteID(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - -class PTextureID : public PInt -{ - DECLARE_CLASS(PTextureID, PInt); -public: - PTextureID(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - -class PColor : public PInt -{ - DECLARE_CLASS(PColor, PInt); -public: - PColor(); -}; - -class PStateLabel : public PInt -{ - DECLARE_CLASS(PStateLabel, PInt); -public: - PStateLabel(); -}; - -// Pointers ----------------------------------------------------------------- - -class PPointer : public PBasicType -{ - DECLARE_CLASS(PPointer, PBasicType); - -public: - typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr); - typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr); - - PPointer(); - PPointer(PType *pointsat, bool isconst = false); - - PType *PointedType; - bool IsConst; - - WriteHandler writer = nullptr; - ReadHandler reader = nullptr; - - void InstallHandlers(WriteHandler w, ReadHandler r) - { - writer = w; - reader = r; - } - - 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; - -protected: - void SetOps(); -}; - -class PStatePointer : public PPointer -{ - DECLARE_CLASS(PStatePointer, PPointer); -public: - PStatePointer(); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; -}; - - -class PObjectPointer : public PPointer -{ - DECLARE_CLASS(PObjectPointer, PPointer); -public: - PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false); - - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; - PClass *PointedClass() const; -}; - - -class PClassPointer : public PPointer -{ - DECLARE_CLASS(PClassPointer, PPointer); -public: - PClassPointer(class PClass *restrict = nullptr); - - class PClass *ClassRestriction; - - bool isCompatible(PType *type); - void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; - bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; - - void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -}; - -// Compound types ----------------------------------------------------------- - -class PEnum : public PInt -{ - DECLARE_CLASS(PEnum, PInt); -public: - PEnum(FName name, PTypeBase *outer); - - PTypeBase *Outer; - FName EnumName; -protected: - PEnum(); -}; - -class PArray : public PCompoundType -{ - DECLARE_CLASS(PArray, PCompoundType); -public: - PArray(PType *etype, unsigned int ecount); - - PType *ElementType; - unsigned int ElementCount; - unsigned int ElementSize; - - 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 *special) override; - void SetPointer(void *base, unsigned offset, TArray *special) override; - -protected: - PArray(); -}; - -class PStaticArray : public PArray -{ - DECLARE_CLASS(PStaticArray, PArray); -public: - PStaticArray(PType *etype); - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; - -protected: - PStaticArray(); -}; - -class PDynArray : public PCompoundType -{ - DECLARE_CLASS(PDynArray, PCompoundType); -public: - PDynArray(PType *etype, PStruct *backing); - - PType *ElementType; - PStruct *BackingType; - - 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) 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(); -}; - -class PMap : public PCompoundType -{ - DECLARE_CLASS(PMap, PCompoundType); -public: - PMap(PType *keytype, PType *valtype); - - PType *KeyType; - PType *ValueType; - - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PMap(); -}; - -class PStruct : public PContainerType -{ - DECLARE_CLASS(PStruct, PContainerType); - -public: - PStruct(FName name, PTypeBase *outer, bool isnative = false); - - bool isNative; - // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. - VMFunction *mConstructor = nullptr; - VMFunction *mDestructor = nullptr; - - virtual PField *AddField(FName name, PType *type, uint32_t flags=0); - virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0); - - 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) override; - void SetPointer(void *base, unsigned offset, TArray *specials) override; - -protected: - PStruct(); -}; - -class PPrototype : public PCompoundType -{ - DECLARE_CLASS(PPrototype, PCompoundType); -public: - PPrototype(const TArray &rettypes, const TArray &argtypes); - - TArray ArgumentTypes; - TArray ReturnTypes; - - size_t PropagateMark(); - virtual bool IsMatch(intptr_t id1, intptr_t id2) const; - virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; -protected: - PPrototype(); -}; - - -// Meta-info for every class derived from DObject --------------------------- +extern FMemArena ClassDataAllocator; enum { TentativeClass = UINT_MAX, }; -class PClassType : public PContainerType -{ - DECLARE_CLASS(PClassType, PContainerType); - -private: - -public: - PClass *Descriptor; - PClassType *ParentType; - - PClassType(PClass *cls = nullptr); - PField *AddField(FName name, PType *type, uint32_t flags = 0) override; - PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; -}; class PClass { @@ -710,107 +144,4 @@ public: static bool bVMOperational; }; -// Type tables -------------------------------------------------------------- - -struct FTypeTable -{ - enum { HASH_SIZE = 1021 }; - - PType *TypeHash[HASH_SIZE]; - - PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); - void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); - void AddType(PType *type); - void Clear(); - - static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); -}; - - -extern FTypeTable TypeTable; - -// Returns a type from the TypeTable. Will create one if it isn't present. -PMap *NewMap(PType *keytype, PType *valuetype); -PArray *NewArray(PType *type, unsigned int count); -PStaticArray *NewStaticArray(PType *type); -PDynArray *NewDynArray(PType *type); -PPointer *NewPointer(PType *type, bool isconst = false); -PPointer *NewPointer(PClass *type, bool isconst = false); -PClassPointer *NewClassPointer(PClass *restrict); -PEnum *NewEnum(FName name, PTypeBase *outer); -PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); -PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); -PClassType *NewClassType(PClass *cls); - -// Built-in types ----------------------------------------------------------- - -extern PErrorType *TypeError; -extern PErrorType *TypeAuto; -extern PVoidType *TypeVoid; -extern PInt *TypeSInt8, *TypeUInt8; -extern PInt *TypeSInt16, *TypeUInt16; -extern PInt *TypeSInt32, *TypeUInt32; -extern PBool *TypeBool; -extern PFloat *TypeFloat32, *TypeFloat64; -extern PString *TypeString; -extern PName *TypeName; -extern PSound *TypeSound; -extern PColor *TypeColor; -extern PTextureID *TypeTextureID; -extern PSpriteID *TypeSpriteID; -extern PStruct *TypeVector2; -extern PStruct *TypeVector3; -extern PStruct *TypeColorStruct; -extern PStruct *TypeStringStruct; -extern PStatePointer *TypeState; -extern PPointer *TypeFont; -extern PStateLabel *TypeStateLabel; -extern PPointer *TypeNullPtr; -extern PPointer *TypeVoidPtr; - -// Enumerations for serializing types in an archive ------------------------- - -inline bool &DObject::BoolVar(FName field) -{ - return *(bool*)ScriptVar(field, TypeBool); -} - -inline int &DObject::IntVar(FName field) -{ - return *(int*)ScriptVar(field, TypeSInt32); -} - -inline FSoundID &DObject::SoundVar(FName field) -{ - return *(FSoundID*)ScriptVar(field, TypeSound); -} - -inline PalEntry &DObject::ColorVar(FName field) -{ - return *(PalEntry*)ScriptVar(field, TypeColor); -} - -inline FName &DObject::NameVar(FName field) -{ - return *(FName*)ScriptVar(field, TypeName); -} - -inline double &DObject::FloatVar(FName field) -{ - return *(double*)ScriptVar(field, TypeFloat64); -} - -inline FString &DObject::StringVar(FName field) -{ - return *(FString*)ScriptVar(field, TypeString); -} - -template -inline T *&DObject::PointerVar(FName field) -{ - return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle. -} - -void RemoveUnusedSymbols(); - #endif diff --git a/src/doomstat.cpp b/src/doomstat.cpp index 49b4d533f..309398331 100644 --- a/src/doomstat.cpp +++ b/src/doomstat.cpp @@ -61,7 +61,6 @@ CUSTOM_CVAR (String, language, "auto", CVAR_ARCHIVE) // [RH] Network arbitrator int Net_Arbitrator = 0; -DEFINE_GLOBAL(Net_Arbitrator); int NextSkill = -1; diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index ec257a310..719fbf2d7 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -31,6 +31,7 @@ #include "statnums.h" #include "serializer.h" #include "doomstat.h" +#include "vm.h" IMPLEMENT_CLASS(DSectorEffect, false, false) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index af1771c5b..5144cf56e 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -40,7 +40,7 @@ #include "doomerrors.h" #include "serializer.h" #include "d_player.h" -#include "virtual.h" +#include "vm.h" static int ThinkCount; @@ -315,7 +315,7 @@ void DThinker::CallPostBeginPlay() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } else { @@ -560,7 +560,7 @@ void DThinker::CallTick() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } else Tick(); } diff --git a/src/events.cpp b/src/events.cpp index 970b68da5..c2ae5f0b4 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -1,5 +1,5 @@ #include "events.h" -#include "virtual.h" +#include "vm.h" #include "r_utility.h" #include "g_levellocals.h" #include "gi.h" @@ -7,6 +7,7 @@ #include "actor.h" #include "c_dispatch.h" #include "d_net.h" +#include "vm.h" DStaticEventHandler* E_FirstEventHandler = nullptr; DStaticEventHandler* E_LastEventHandler = nullptr; @@ -626,7 +627,7 @@ void DStaticEventHandler::OnRegister() if (func == DStaticEventHandler_OnRegister_VMPtr) return; VMValue params[1] = { (DStaticEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -638,7 +639,7 @@ void DStaticEventHandler::OnUnregister() if (func == DStaticEventHandler_OnUnregister_VMPtr) return; VMValue params[1] = { (DStaticEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -660,7 +661,7 @@ void DStaticEventHandler::WorldLoaded() return; FWorldEvent e = E_SetupWorldEvent(); VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -673,7 +674,7 @@ void DStaticEventHandler::WorldUnloaded() return; FWorldEvent e = E_SetupWorldEvent(); VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -687,7 +688,7 @@ void DStaticEventHandler::WorldThingSpawned(AActor* actor) FWorldEvent e = E_SetupWorldEvent(); e.Thing = actor; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -702,7 +703,7 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor) e.Thing = actor; e.Inflictor = inflictor; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -716,7 +717,7 @@ void DStaticEventHandler::WorldThingRevived(AActor* actor) FWorldEvent e = E_SetupWorldEvent(); e.Thing = actor; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -735,7 +736,7 @@ void DStaticEventHandler::WorldThingDamaged(AActor* actor, AActor* inflictor, AA e.DamageFlags = flags; e.DamageAngle = angle; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -749,7 +750,7 @@ void DStaticEventHandler::WorldThingDestroyed(AActor* actor) FWorldEvent e = E_SetupWorldEvent(); e.Thing = actor; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -762,7 +763,7 @@ void DStaticEventHandler::WorldLightning() return; FWorldEvent e = E_SetupWorldEvent(); VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -774,7 +775,7 @@ void DStaticEventHandler::WorldTick() if (func == DStaticEventHandler_WorldTick_VMPtr) return; VMValue params[1] = { (DStaticEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -799,7 +800,7 @@ void DStaticEventHandler::RenderFrame() return; FRenderEvent e = E_SetupRenderEvent(); VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -813,7 +814,7 @@ void DStaticEventHandler::RenderOverlay(EHudState state) FRenderEvent e = E_SetupRenderEvent(); e.HudState = int(state); VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -826,7 +827,7 @@ void DStaticEventHandler::PlayerEntered(int num, bool fromhub) return; FPlayerEvent e = { num, fromhub }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -839,7 +840,7 @@ void DStaticEventHandler::PlayerRespawned(int num) return; FPlayerEvent e = { num, false }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -852,7 +853,7 @@ void DStaticEventHandler::PlayerDied(int num) return; FPlayerEvent e = { num, false }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -865,7 +866,7 @@ void DStaticEventHandler::PlayerDisconnected(int num) return; FPlayerEvent e = { num, false }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } @@ -921,7 +922,7 @@ bool DStaticEventHandler::UiProcess(const event_t* ev) int processed; VMReturn results[1] = { &processed }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, results, 1, nullptr); + VMCall(func, params, 2, results, 1); return !!processed; } @@ -969,7 +970,7 @@ bool DStaticEventHandler::InputProcess(const event_t* ev) int processed; VMReturn results[1] = { &processed }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, results, 1, nullptr); + VMCall(func, params, 2, results, 1); return !!processed; } @@ -984,7 +985,7 @@ void DStaticEventHandler::UiTick() if (func == DStaticEventHandler_UiTick_VMPtr) return; VMValue params[1] = { (DStaticEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -1008,7 +1009,7 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int e.IsManual = manual; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } else @@ -1029,7 +1030,7 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int e.IsManual = manual; VMValue params[2] = { (DStaticEventHandler*)this, &e }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 17cd67a7a..16b818ba7 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -85,6 +85,7 @@ #include "serializer.h" #include "w_zip.h" #include "resourcefiles/resourcefile.h" +#include "vm.h" #include @@ -3010,3 +3011,5 @@ DEFINE_GLOBAL(skyflatnum) DEFINE_GLOBAL_NAMED(bglobal.freeze, globalfreeze) DEFINE_GLOBAL(gametic) DEFINE_GLOBAL(demoplayback) +DEFINE_GLOBAL(automapactive); +DEFINE_GLOBAL(Net_Arbitrator); diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 701b98b00..8b2ac54c9 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -43,7 +43,7 @@ #include "w_wad.h" #include "doomstat.h" #include "v_font.h" - +#include "vm.h" //=========================================================================== // diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 0a44e6d14..5d2617881 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -19,9 +19,10 @@ #include "d_player.h" #include "p_spec.h" #include "serializer.h" -#include "virtual.h" +#include "vm.h" #include "c_functions.h" #include "g_levellocals.h" +#include "vm.h" EXTERN_CVAR(Bool, sv_unlimited_pickup) @@ -237,7 +238,7 @@ double AInventory::GetSpeedFactor() VMValue params[1] = { (DObject*)self }; double retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); factor *= retval; } self = self->Inventory; @@ -261,7 +262,7 @@ bool AInventory::GetNoTeleportFreeze () VMValue params[1] = { (DObject*)self }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); if (retval) return true; } self = self->Inventory; @@ -282,7 +283,7 @@ bool AInventory::CallUse(bool pickup) VMValue params[2] = { (DObject*)this, pickup }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return !!retval; } return false; @@ -347,7 +348,7 @@ void AInventory::DepleteOrDestroy () IFVIRTUAL(AInventory, DepleteOrDestroy) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -367,7 +368,7 @@ PalEntry AInventory::CallGetBlend() VMValue params[1] = { (DObject*)this }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); return retval; } else return 0; @@ -479,7 +480,7 @@ bool AInventory::CallTryPickup(AActor *toucher, AActor **toucher_return) AActor *tret; ret[0].IntAt(&res); ret[1].PointerAt((void**)&tret); - GlobalVMStack.Call(func, params, 2, ret, 2); + VMCall(func, params, 2, ret, 2); if (toucher_return) *toucher_return = tret; return !!res; } diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index e4079121a..5086d7832 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -52,11 +52,7 @@ #include "g_level.h" #include "d_net.h" #include "serializer.h" -#include "thingdef.h" -#include "virtual.h" - - -extern FFlagDef WeaponFlagDefs[]; +#include "vm.h" IMPLEMENT_CLASS(AWeapon, false, true) @@ -66,7 +62,6 @@ IMPLEMENT_POINTERS_START(AWeapon) IMPLEMENT_POINTER(SisterWeapon) IMPLEMENT_POINTERS_END -DEFINE_FIELD(AWeapon, WeaponFlags) DEFINE_FIELD(AWeapon, AmmoType1) DEFINE_FIELD(AWeapon, AmmoType2) DEFINE_FIELD(AWeapon, AmmoGive1) @@ -99,6 +94,7 @@ DEFINE_FIELD(AWeapon, Crosshair) DEFINE_FIELD(AWeapon, GivenAsMorphWeapon) DEFINE_FIELD(AWeapon, bAltFire) DEFINE_FIELD(AWeapon, SlotNumber) +DEFINE_FIELD(AWeapon, WeaponFlags) DEFINE_FIELD_BIT(AWeapon, WeaponFlags, bDehAmmo, WIF_DEHAMMO) //=========================================================================== @@ -404,7 +400,7 @@ FState *AWeapon::GetUpState () VMReturn ret; FState *retval; ret.PointerAt((void**)&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); return retval; } return nullptr; @@ -424,7 +420,7 @@ FState *AWeapon::GetDownState () VMReturn ret; FState *retval; ret.PointerAt((void**)&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); return retval; } return nullptr; @@ -444,7 +440,7 @@ FState *AWeapon::GetReadyState () VMReturn ret; FState *retval; ret.PointerAt((void**)&retval); - GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + VMCall(func, params, 1, &ret, 1); return retval; } return nullptr; @@ -464,7 +460,7 @@ FState *AWeapon::GetAtkState (bool hold) VMReturn ret; FState *retval; ret.PointerAt((void**)&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return retval; } return nullptr; @@ -484,7 +480,7 @@ FState *AWeapon::GetAltAtkState (bool hold) VMReturn ret; FState *retval; ret.PointerAt((void**)&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return retval; } return nullptr; diff --git a/src/g_level.cpp b/src/g_level.cpp index ecde760f3..46248deca 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -84,7 +84,7 @@ #include "r_utility.h" #include "p_spec.h" #include "serializer.h" -#include "virtual.h" +#include "vm.h" #include "events.h" #include "gi.h" @@ -92,6 +92,7 @@ #include "g_hub.h" #include "g_levellocals.h" #include "actorinlines.h" +#include "vm.h" #include @@ -1318,8 +1319,7 @@ void G_FinishTravel () IFVIRTUALPTR(inv, AInventory, Travelled) { VMValue params[1] = { inv }; - VMFrameStack stack; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 575e7027c..71f796a89 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -11,6 +11,7 @@ #include "templates.h" #include "serializer.h" #include "r_data/r_translate.h" +#include "vm.h" //---------------------------------------------------------------------------- // diff --git a/src/g_shared/a_dynlight.cpp b/src/g_shared/a_dynlight.cpp index 95e87baf4..4aaa75fa5 100644 --- a/src/g_shared/a_dynlight.cpp +++ b/src/g_shared/a_dynlight.cpp @@ -60,7 +60,7 @@ #include "p_local.h" #include "c_dispatch.h" #include "g_level.h" -#include "scripting/thingdef.h" +#include "thingdef.h" #include "i_system.h" #include "templates.h" #include "doomdata.h" @@ -74,6 +74,7 @@ #include "actorinlines.h" #include "c_cvars.h" #include "gl/system//gl_interface.h" +#include "vm.h" EXTERN_CVAR(Int, vid_renderer) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index f7177165e..3b68e8c2b 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -15,7 +15,8 @@ #include "d_player.h" #include "r_data/sprites.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" +#include "vm.h" static FRandom pr_morphmonst ("MorphMonster"); @@ -612,8 +613,7 @@ void EndAllPowerupEffects(AInventory *item) IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect) { VMValue params[1] = { item }; - VMFrameStack stack; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } item = item->Inventory; @@ -638,8 +638,7 @@ void InitAllPowerupEffects(AInventory *item) IFVIRTUALPTRNAME(item, NAME_Powerup, InitEffect) { VMValue params[1] = { item }; - VMFrameStack stack; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } item = item->Inventory; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 2c41b2099..5c0919820 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -40,6 +40,7 @@ #include "doomstat.h" #include "serializer.h" #include "a_pickups.h" +#include "vm.h" static FRandom pr_spot ("SpecialSpot"); static FRandom pr_spawnmace ("SpawnMace"); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index c414a9275..8ac35da24 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -54,7 +54,7 @@ #include "r_utility.h" #include "cmdlib.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #include @@ -1093,7 +1093,7 @@ static void DrawPowerups(player_t *CPlayer) VMValue param[] = { item }; int rv; VMReturn ret(&rv); - GlobalVMStack.Call(func, param, 1, &ret, 1); + VMCall(func, param, 1, &ret, 1); auto tex = FSetTextureID(rv); if (!tex.isValid()) continue; auto texture = TexMan(tex); diff --git a/src/g_skill.cpp b/src/g_skill.cpp index befd1115b..6e23c9523 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -44,6 +44,7 @@ #include "m_fixed.h" #include "gstrings.h" #include "g_levellocals.h" +#include "vm.h" TArray AllSkills; int DefaultSkill = -1; diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index a46911217..6d9baea24 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -57,7 +57,7 @@ #include "gstrings.h" #include "cmdlib.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index cffe67b11..63c9d9ed8 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -1441,7 +1441,7 @@ class CommandDrawNumber : public CommandDrawString VMValue params[] = { statusBar->CPlayer->mo, inventoryItem }; int retv; VMReturn ret(&retv); - GlobalVMStack.Call(func, params, 2, &ret, 1); + VMCall(func, params, 2, &ret, 1); num = retv < 0? 0 : retv / TICRATE + 1; break; } @@ -2738,7 +2738,7 @@ class CommandDrawBar : public SBarInfoCommand int ival; ret[0].IntAt(&ival); ret[1].IntAt(&max); - GlobalVMStack.Call(func, params, 2, ret, 2); + VMCall(func, params, 2, ret, 2); value = ival + 1; max++; break; diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 2514cd8d2..1afe8d46d 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -57,7 +57,7 @@ #include "r_utility.h" #include "cmdlib.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #include "p_acs.h" #include "r_data/r_translate.h" #include "sbarinfo.h" @@ -329,7 +329,7 @@ void ST_CreateStatusBar(bool bTitleLevel) IFVIRTUALPTR(StatusBar, DBaseStatusBar, Init) { VMValue params[] = { StatusBar }; - GlobalVMStack.Call(func, params, 1, nullptr, 0); + VMCall(func, params, 1, nullptr, 0); } GC::WriteBarrier(StatusBar); @@ -560,7 +560,7 @@ void DBaseStatusBar::AttachToPlayer(player_t *player) IFVIRTUAL(DBaseStatusBar, AttachToPlayer) { VMValue params[] = { (DObject*)this, player }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } } @@ -641,7 +641,7 @@ void DBaseStatusBar::CallTick() IFVIRTUAL(DBaseStatusBar, Tick) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } else Tick(); mugshot.Tick(CPlayer); @@ -973,7 +973,7 @@ void DBaseStatusBar::Draw (EHudState state) IFVIRTUAL(DBaseStatusBar, DrawMyPos) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } V_SetBorderNeedRefresh(); } @@ -990,7 +990,7 @@ void DBaseStatusBar::Draw (EHudState state) IFVIRTUAL(DBaseStatusBar, DrawAutomapHUD) { VMValue params[] = { (DObject*)this, r_viewpoint.TicFrac }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } } } @@ -1008,7 +1008,7 @@ void DBaseStatusBar::CallDraw(EHudState state) IFVIRTUAL(DBaseStatusBar, Draw) { VMValue params[] = { (DObject*)this, state, r_viewpoint.TicFrac }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } else Draw(state); screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. @@ -1073,7 +1073,7 @@ bool DBaseStatusBar::MustDrawLog(EHudState state) VMValue params[] = { (DObject*)this }; int rv; VMReturn ret(&rv); - GlobalVMStack.Call(func, params, countof(params), &ret, 1); + VMCall(func, params, countof(params), &ret, 1); return !!rv; } return true; @@ -1095,7 +1095,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b { FString statestring = stateName; VMValue params[] = { (DObject*)this, &statestring, waitTillDone, reset }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } } @@ -1133,7 +1133,7 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) IFVIRTUAL(DBaseStatusBar, DrawPowerups) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0); + VMCall(func, params, 1, nullptr, 0); } fullscreenOffsets = saved; } @@ -1261,7 +1261,7 @@ void DBaseStatusBar::FlashItem (const PClass *itemtype) IFVIRTUAL(DBaseStatusBar, FlashItem) { VMValue params[] = { (DObject*)this, (PClass*)itemtype }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } } @@ -1270,7 +1270,7 @@ void DBaseStatusBar::NewGame () IFVIRTUAL(DBaseStatusBar, NewGame) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } mugshot.Reset(); } @@ -1280,7 +1280,7 @@ void DBaseStatusBar::ShowPop(int pop) IFVIRTUAL(DBaseStatusBar, ShowPop) { VMValue params[] = { (DObject*)this, pop }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } } @@ -1319,7 +1319,7 @@ void DBaseStatusBar::CallScreenSizeChanged() IFVIRTUAL(DBaseStatusBar, ScreenSizeChanged) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0); + VMCall(func, params, countof(params), nullptr, 0); } else ScreenSizeChanged(); } diff --git a/src/gi.cpp b/src/gi.cpp index ac4f5117c..8dea1e577 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -42,6 +42,7 @@ #include "i_system.h" #include "v_video.h" #include "g_level.h" +#include "vm.h" gameinfo_t gameinfo; diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index 978dd1696..e0b065a13 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -33,6 +33,7 @@ #include "c_dispatch.h" #include "r_state.h" #include "actor.h" +#include "cmdlib.h" #ifdef _WIN32 #include "win32gliface.h" #endif diff --git a/src/info.cpp b/src/info.cpp index 7f677bf3a..7dd40c1ea 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -55,6 +55,8 @@ #include "d_player.h" #include "doomerrors.h" #include "events.h" +#include "types.h" +#include "vm.h" extern void LoadActors (); extern void InitBotStuff(); @@ -128,35 +130,35 @@ void FState::SetAction(const char *name) bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) { - if (ActionFunc != NULL) + if (ActionFunc != nullptr) { ActionCycles.Clock(); VMValue params[3] = { self, stateowner, VMValue(info) }; // If the function returns a state, store it at *stateret. - // If it doesn't return a state but stateret is non-NULL, we need - // to set *stateret to NULL. - if (stateret != NULL) + // If it doesn't return a state but stateret is non-nullptr, we need + // to set *stateret to nullptr. + if (stateret != nullptr) { - *stateret = NULL; - if (ActionFunc->Proto == NULL || + *stateret = nullptr; + if (ActionFunc->Proto == nullptr || ActionFunc->Proto->ReturnTypes.Size() == 0 || ActionFunc->Proto->ReturnTypes[0] != TypeState) { - stateret = NULL; + stateret = nullptr; } } try { - if (stateret == NULL) + if (stateret == nullptr) { - GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); + VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); } else { VMReturn ret; ret.PointerAt((void **)stateret); - GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); + VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1); } } catch (CVMAbortException &err) @@ -331,11 +333,11 @@ void AActor::Finalize(FStateDefinitions &statedef) } catch (CRecoverableError &) { - statedef.MakeStateDefines(NULL); + statedef.MakeStateDefines(nullptr); throw; } statedef.InstallStates(GetClass(), defaults); - statedef.MakeStateDefines(NULL); + statedef.MakeStateDefines(nullptr); } //========================================================================== @@ -350,7 +352,7 @@ void PClassActor::RegisterIDs() { PClassActor *cls = PClass::FindActor(TypeName); - if (cls == NULL) + if (cls == nullptr) { Printf(TEXTCOLOR_RED"The actor '%s' has been hidden by a non-actor of the same name\n", TypeName.GetChars()); return; @@ -381,7 +383,7 @@ void PClassActor::RegisterIDs() if (DoomEdNum != -1) { FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum); - if (oldent != NULL && oldent->Special == -2) + if (oldent != nullptr && oldent->Special == -2) { Printf(TEXTCOLOR_RED"Editor number %d defined twice for classes '%s' and '%s'\n", DoomEdNum, cls->TypeName.GetChars(), oldent->Type->TypeName.GetChars()); } @@ -411,7 +413,7 @@ PClassActor *PClassActor::GetReplacement(bool lookskill) if (lookskill && AllSkills.Size() > (unsigned)gameskill) { skillrepname = AllSkills[gameskill].GetReplacement(TypeName); - if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) + if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == nullptr) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "class %s is replaced by non-existent class %s\n" @@ -467,7 +469,7 @@ PClassActor *PClassActor::GetReplacee(bool lookskill) if (lookskill && AllSkills.Size() > (unsigned)gameskill) { skillrepname = AllSkills[gameskill].GetReplacedBy(TypeName); - if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) + if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == nullptr) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "non-existent class %s is replaced by class %s\n" @@ -488,7 +490,7 @@ PClassActor *PClassActor::GetReplacee(bool lookskill) // potential infinite recursion. ActorInfo()->Replacee = nullptr; PClassActor *rep = savedrep; - if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != NULL)) + if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != nullptr)) { rep = PClass::FindActor(skillrepname); } @@ -578,7 +580,7 @@ static void SummonActor (int command, int command2, FCommandLine argv) if (argv.argc() > 1) { PClassActor *type = PClass::FindActor(argv[1]); - if (type == NULL) + if (type == nullptr) { Printf ("Unknown actor '%s'\n", argv[1]); return; diff --git a/src/info.h b/src/info.h index 01a1a3f47..d167631cf 100644 --- a/src/info.h +++ b/src/info.h @@ -286,6 +286,9 @@ struct FActorInfo } }; +// This is now merely a wrapper that adds actor-specific functionality to PClass. +// No objects of this type will be created ever - its only use is to static_casr +// PClass to it. class PClassActor : public PClass { protected: @@ -293,9 +296,6 @@ public: static void StaticInit (); static void StaticSetActorNums (); - PClassActor(); - ~PClassActor(); - void BuildDefaults(); void ApplyDefaults(uint8_t *defaults); void RegisterIDs(); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 437e7ff89..b667415a8 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -48,7 +48,7 @@ #include "r_utility.h" #include "a_morph.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #include "events.h" #include "p_acs.h" @@ -479,7 +479,7 @@ void cht_DoCheat (player_t *player, int cheat) VMReturn ret; int oldpieces = 1; ret.IntAt(&oldpieces); - GlobalVMStack.Call(gsp, params, 1, &ret, 1, nullptr); + VMCall(gsp, params, 1, &ret, 1); item = player->mo->FindInventory(NAME_Sigil); if (item != NULL) @@ -604,7 +604,7 @@ void cht_Give (player_t *player, const char *name, int amount) { FString namestr = name; VMValue params[3] = { player->mo, &namestr, amount }; - GlobalVMStack.Call(func, params, 3, nullptr, 0); + VMCall(func, params, 3, nullptr, 0); } } @@ -616,7 +616,7 @@ void cht_Take (player_t *player, const char *name, int amount) { FString namestr = name; VMValue params[3] = { player->mo, &namestr, amount }; - GlobalVMStack.Call(func, params, 3, nullptr, 0); + VMCall(func, params, 3, nullptr, 0); } } diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index 59b3ad990..fb50834c0 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -50,6 +50,7 @@ #include "d_gui.h" #include "i_music.h" #include "m_joy.h" +#include "vm.h" static TArray Joysticks; diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index fdca9abc8..f76654165 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -48,6 +48,7 @@ #include "d_gui.h" #include "serializer.h" #include "resourcefiles/resourcefile.h" +#include "vm.h" // Save name length limit for old binary formats. #define OLDSAVESTRINGSIZE 24 diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 5f7d4bfe5..54bc8af07 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -55,7 +55,7 @@ #include "r_utility.h" #include "menu/menu.h" #include "textures/textures.h" -#include "virtual.h" +#include "vm.h" #include "events.h" // @@ -182,7 +182,7 @@ bool DMenu::CallResponder(event_t *ev) VMValue params[] = { (DObject*)this, &e }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return !!retval; } } @@ -194,7 +194,7 @@ bool DMenu::CallResponder(event_t *ev) VMValue params[] = { (DObject*)this, &e }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return !!retval; } } @@ -214,7 +214,7 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) VMValue params[] = { (DObject*)this, mkey, fromcontroller }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + VMCall(func, params, 3, &ret, 1); return !!retval; } else return false; @@ -246,7 +246,7 @@ void DMenu::Close () IFVIRTUALPTR(CurrentMenu, DMenu, OnReturn) { VMValue params[] = { CurrentMenu }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -274,7 +274,7 @@ void DMenu::CallTicker() IFVIRTUAL(DMenu, Ticker) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -284,7 +284,7 @@ void DMenu::CallDrawer() IFVIRTUAL(DMenu, Drawer) { VMValue params[] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. } } @@ -296,7 +296,7 @@ bool DMenu::TranslateKeyboardEvents() VMValue params[] = { (DObject*)this }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); + VMCall(func, params, countof(params), &ret, 1); return !!retval; } return true; @@ -472,7 +472,7 @@ void M_SetMenu(FName menu, int param) IFVIRTUALPTRNAME(newmenu, "ListMenu", Init) { VMValue params[3] = { newmenu, CurrentMenu, ld }; - GlobalVMStack.Call(func, params, 3, nullptr, 0); + VMCall(func, params, 3, nullptr, 0); } M_ActivateMenu(newmenu); } @@ -488,7 +488,7 @@ void M_SetMenu(FName menu, int param) IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init) { VMValue params[3] = { newmenu, CurrentMenu, ld }; - GlobalVMStack.Call(func, params, 3, nullptr, 0); + VMCall(func, params, 3, nullptr, 0); } M_ActivateMenu(newmenu); } @@ -506,7 +506,7 @@ void M_SetMenu(FName menu, int param) IFVIRTUALPTRNAME(newmenu, "GenericMenu", Init) { VMValue params[3] = { newmenu, CurrentMenu }; - GlobalVMStack.Call(func, params, 2, nullptr, 0); + VMCall(func, params, 2, nullptr, 0); } M_ActivateMenu(newmenu); return; @@ -1058,7 +1058,7 @@ CCMD(undocolorpic) IFVIRTUALPTR(CurrentMenu, DMenu, ResetColor) { VMValue params[] = { (DObject*)CurrentMenu }; - GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr); + VMCall(func, params, countof(params), nullptr, 0); } } } @@ -1128,7 +1128,7 @@ DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v) FString namestr = name; VMValue params[] = { p, &namestr, v }; auto f = dyn_cast(c->FindSymbol("Init", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1139,7 +1139,7 @@ DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickCo FString namestr = label; VMValue params[] = { p, &namestr, joy }; auto f = dyn_cast(c->FindSymbol("Init", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1150,7 +1150,7 @@ DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int ce FString namestr = label; VMValue params[] = { p, &namestr, cmd.GetIndex(), center }; auto f = dyn_cast(c->FindSymbol("Init", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1161,7 +1161,7 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi FString namestr = label; VMValue params[] = { p, &namestr, cmd.GetIndex(), bindings }; auto f = dyn_cast(c->FindSymbol("Init", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1172,7 +1172,7 @@ DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotk FString keystr = FString(char(hotkey)); VMValue params[] = { p, x, y, height, tex.GetIndex(), &keystr, command.GetIndex(), param }; auto f = dyn_cast(c->FindSymbol("InitDirect", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1184,7 +1184,7 @@ DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotke FString textstr = text; VMValue params[] = { p, x, y, height, &keystr, &textstr, font, int(color1.d), int(color2.d), command.GetIndex(), param }; auto f = dyn_cast(c->FindSymbol("InitDirect", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenuItemBase*)p; } @@ -1195,7 +1195,7 @@ bool DMenuItemBase::Activate() VMValue params[] = { (DObject*)this }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); + VMCall(func, params, countof(params), &ret, 1); return !!retval; } return false; @@ -1209,7 +1209,7 @@ bool DMenuItemBase::SetString(int i, const char *s) VMValue params[] = { (DObject*)this, i, &namestr }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); + VMCall(func, params, countof(params), &ret, 1); return !!retval; } return false; @@ -1223,7 +1223,7 @@ bool DMenuItemBase::GetString(int i, char *s, int len) int retval; FString retstr; VMReturn ret[2]; ret[0].IntAt(&retval); ret[1].StringAt(&retstr); - GlobalVMStack.Call(func, params, countof(params), ret, 2, nullptr); + VMCall(func, params, countof(params), ret, 2); strncpy(s, retstr, len); return !!retval; } @@ -1238,7 +1238,7 @@ bool DMenuItemBase::SetValue(int i, int value) VMValue params[] = { (DObject*)this, i, value }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); + VMCall(func, params, countof(params), &ret, 1); return !!retval; } return false; @@ -1251,7 +1251,7 @@ bool DMenuItemBase::GetValue(int i, int *pvalue) VMValue params[] = { (DObject*)this, i }; int retval[2]; VMReturn ret[2]; ret[0].IntAt(&retval[0]); ret[1].IntAt(&retval[1]); - GlobalVMStack.Call(func, params, countof(params), ret, 2, nullptr); + VMCall(func, params, countof(params), ret, 2); *pvalue = retval[1]; return !!retval[0]; } diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 490f8ec65..5a2f18974 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -51,6 +51,8 @@ #include "gi.h" #include "i_sound.h" #include "cmdlib.h" +#include "vm.h" +#include "types.h" @@ -480,7 +482,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) } DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); params[0] = item; - GlobalVMStack.Call(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); + VMCall(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); desc->mItems.Push((DMenuItemBase*)item); if (cls->IsDescendantOf("ListMenuItemSelectable")) @@ -837,7 +839,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew(); params[0] = item; - GlobalVMStack.Call(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); + VMCall(func->Variants[0].Implementation, ¶ms[0], params.Size(), nullptr, 0); desc->mItems.Push((DMenuItemBase*)item); success = true; diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index a7a69dbb5..368420964 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -45,6 +45,7 @@ #include "st_start.h" #include "c_dispatch.h" #include "g_game.h" +#include "vm.h" EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] @@ -71,7 +72,7 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, VMValue params[] = { p, parent, &namestr, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; auto f = dyn_cast(c->FindSymbol("Init", false)); - GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); + VMCall(f->Variants[0].Implementation, params, countof(params), nullptr, 0); return (DMenu*)p; } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index fa5796a45..55f85c221 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -47,6 +47,7 @@ #include "r_state.h" #include "r_data/r_translate.h" #include "v_text.h" +#include "vm.h" EXTERN_CVAR(Int, team) EXTERN_CVAR(Float, autoaim) diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index b23798727..5f139f0af 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -53,6 +53,7 @@ #include "m_joy.h" #include "sbar.h" #include "hardware.h" +#include "vm.h" /*======================================= * diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0feb013f4..55dfdd8e6 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -87,6 +87,8 @@ #include "g_levellocals.h" #include "actorinlines.h" #include "stats.h" +#include "types.h" +#include "vm.h" // P-codes for ACS scripts enum @@ -5431,7 +5433,7 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) // The return value can be the same types as the parameter types, plus void if (func->Proto->ReturnTypes.Size() == 0) { - GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0); + VMCall(func, ¶ms[0], params.Size(), nullptr, 0); } else { @@ -5439,7 +5441,7 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) if (rettype == TypeSInt32 || rettype == TypeBool || rettype == TypeColor || rettype == TypeName || rettype == TypeSound) { VMReturn ret(&retval); - GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + VMCall(func, ¶ms[0], params.Size(), &ret, 1); if (rettype == TypeName) { retval = GlobalACSStrings.AddString(FName(ENamedName(retval))); @@ -5453,20 +5455,20 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args) { double d; VMReturn ret(&d); - GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + VMCall(func, ¶ms[0], params.Size(), &ret, 1); retval = DoubleToACS(d); } else if (rettype == TypeString) { FString d; VMReturn ret(&d); - GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1); + VMCall(func, ¶ms[0], params.Size(), &ret, 1); retval = GlobalACSStrings.AddString(d); } else { // All other return values can not be handled so ignore them. - GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0); + VMCall(func, ¶ms[0], params.Size(), nullptr, 0); } } } @@ -6910,7 +6912,7 @@ static void SetMarineWeapon(AActor *marine, int weapon) if (smw) { VMValue params[2] = { marine, weapon }; - GlobalVMStack.Call(smw, params, 2, nullptr, 0, nullptr); + VMCall(smw, params, 2, nullptr, 0); } } @@ -6921,7 +6923,7 @@ static void SetMarineSprite(AActor *marine, PClassActor *source) if (sms) { VMValue params[2] = { marine, source }; - GlobalVMStack.Call(sms, params, 2, nullptr, 0, nullptr); + VMCall(sms, params, 2, nullptr, 0); } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index a23316bd1..8fe698a2f 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -82,6 +82,8 @@ #include "r_utility.h" #include "sbar.h" #include "actorinlines.h" +#include "vm.h" +#include "types.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -182,7 +184,7 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) } try { - GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + VMCall(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); } catch (CVMAbortException &err) { diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 4c2c509e8..c7bc715f2 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -33,6 +33,7 @@ #include "p_spec.h" #include "g_levellocals.h" #include "textures.h" +#include "vm.h" //============================================================================ // diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 08399fe49..bbd9281b7 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -61,7 +61,7 @@ #include "p_local.h" #include "menu/menu.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #include "actorinlines.h" // The conversations as they exist inside a SCRIPTxx lump. @@ -867,7 +867,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang { VMValue params[] = { cmenu, CurNode, pc->player, StaticLastReply }; VMReturn ret(&ConversationMenuY); - GlobalVMStack.Call(func, params, countof(params), &ret, 1); + VMCall(func, params, countof(params), &ret, 1); } if (CurNode != PrevNode) diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 20579ced4..81a1bc5d6 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -54,6 +54,7 @@ #include "d_player.h" #include "r_utility.h" #include "g_levellocals.h" +#include "vm.h" CVAR (Int, cl_rockettrails, 1, CVAR_ARCHIVE); CVAR (Bool, r_rail_smartspiral, 0, CVAR_ARCHIVE); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 8aed0370e..6c25bd46d 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -52,7 +52,7 @@ #include "p_checkposition.h" #include "math/cmath.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" #include "actorinlines.h" #include "gi.h" @@ -3329,7 +3329,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c VMValue params[2] = { inv, source }; int retval; VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); if (retval) { // The special action indicates that the item should not spawn diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 8f7d935ee..918419fbe 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -33,6 +33,7 @@ #include "p_spec.h" #include "r_data/r_interpolate.h" #include "g_levellocals.h" +#include "vm.h" //========================================================================== // diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b6bf36a08..6de00eb37 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -58,7 +58,7 @@ #include "d_net.h" #include "d_netinf.h" #include "a_morph.h" -#include "virtual.h" +#include "vm.h" #include "g_levellocals.h" #include "events.h" #include "actorinlines.h" @@ -248,7 +248,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) }; FString ret; VMReturn rett(&ret); - GlobalVMStack.Call(func, params, countof(params), &rett, 1); + VMCall(func, params, countof(params), &rett, 1); if (ret.IsNotEmpty()) message = ret; } } @@ -326,7 +326,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) IFVIRTUALPTR(item, AInventory, OwnerDied) { VMValue params[1] = { item }; - GlobalVMStack.Call(func, params, 1, nullptr, 0); + VMCall(func, params, 1, nullptr, 0); } item = next; } @@ -367,7 +367,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) { VMValue params[] = { (DObject*)this }; VMReturn ret(&Height); - GlobalVMStack.Call(func, params, 1, &ret, 1); + VMCall(func, params, 1, &ret, 1); } // [RH] If the thing has a special, execute and remove it @@ -733,7 +733,7 @@ void AActor::CallDie(AActor *source, AActor *inflictor, int dmgflags) IFVIRTUAL(AActor, Die) { VMValue params[4] = { (DObject*)this, source, inflictor, dmgflags }; - GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr); + VMCall(func, params, 4, nullptr, 0); } else return Die(source, inflictor, dmgflags); } @@ -1421,7 +1421,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da { VMValue params[] = { source, target, draindmg, mod.GetIndex() }; VMReturn ret(&draindmg); - GlobalVMStack.Call(func, params, countof(params), &ret, 1); + VMCall(func, params, countof(params), &ret, 1); } if (P_GiveBody(source, draindmg)) { @@ -1618,7 +1618,7 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, VMReturn ret; int retval; ret.IntAt(&retval); - GlobalVMStack.Call(func, params, 7, &ret, 1, nullptr); + VMCall(func, params, 7, &ret, 1); return retval; } else @@ -1770,7 +1770,7 @@ bool AActor::CallOkayToSwitchTarget(AActor *other) VMValue params[] = { (DObject*)this, other }; int retv; VMReturn ret(&retv); - GlobalVMStack.Call(func, params, 2, &ret, 1); + VMCall(func, params, 2, &ret, 1); return !!retv; } return OkayToSwitchTarget(other); diff --git a/src/p_linkedsectors.cpp b/src/p_linkedsectors.cpp index 7ac614f2e..11e520a0d 100644 --- a/src/p_linkedsectors.cpp +++ b/src/p_linkedsectors.cpp @@ -38,6 +38,7 @@ #include "p_lnspec.h" #include "p_spec.h" #include "g_levellocals.h" +#include "vm.h" enum { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 39b97f1d8..12a29dd3b 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -62,6 +62,7 @@ #include "fragglescript/t_fs.h" #include "p_spec.h" #include "g_levellocals.h" +#include "vm.h" // Remaps EE sector change types to Generic_Floor values. According to the Eternity Wiki: /* diff --git a/src/p_map.cpp b/src/p_map.cpp index d2d98d237..dd00519e2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -47,7 +47,7 @@ #include "r_utility.h" #include "p_blockmap.h" #include "p_3dmidtex.h" -#include "virtual.h" +#include "vm.h" #include "s_sound.h" #include "decallib.h" @@ -154,7 +154,7 @@ bool P_CanCollideWith(AActor *tmthing, AActor *thing) VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; if (func != nullptr) { - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + VMCall(func, params, 3, &ret, 1); if (!retval) return false; } std::swap(params[0].a, params[1].a); @@ -165,7 +165,7 @@ bool P_CanCollideWith(AActor *tmthing, AActor *thing) func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; if (func != nullptr) { - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + VMCall(func, params, 3, &ret, 1); if (!retval) return false; } return true; @@ -5302,7 +5302,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end, VMValue params[] = { mobj, usething }; int ret; VMReturn vret(&ret); - GlobalVMStack.Call(func, params, 2, &vret, 1); + VMCall(func, params, 2, &vret, 1); if (ret) return true; } continue; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index fc31d60ca..21ed99c61 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -47,6 +47,7 @@ #include "templates.h" #include "po_man.h" #include "g_levellocals.h" +#include "vm.h" sector_t *P_PointInSectorBuggy(double x, double y); int P_VanillaPointOnDivlineSide(double x, double y, const divline_t* line); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f702606ce..afaad56e9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -68,7 +68,7 @@ #include "r_utility.h" #include "thingdef.h" #include "d_player.h" -#include "virtual.h" +#include "vm.h" #include "g_levellocals.h" #include "a_morph.h" #include "events.h" @@ -153,9 +153,6 @@ AActor::~AActor () // Use Destroy() instead. } -extern FFlagDef InternalActorFlagDefs[]; -extern FFlagDef ActorFlagDefs[]; - DEFINE_FIELD(AActor, snext) DEFINE_FIELD(AActor, player) DEFINE_FIELD_NAMED(AActor, __Pos, pos) @@ -841,7 +838,7 @@ void AActor::RemoveInventory(AInventory *item) IFVIRTUALPTR(item, AInventory, DetachFromOwner) { VMValue params[1] = { item }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } item->Owner = NULL; @@ -1109,7 +1106,7 @@ AInventory *AActor::DropInventory (AInventory *item, int amt) { VMValue params[] = { (DObject*)item, amt }; VMReturn ret((void**)&drop); - GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr); + VMCall(func, params, countof(params), &ret, 1); } if (drop == nullptr) return NULL; drop->SetOrigin(PosPlusZ(10.), false); @@ -1681,7 +1678,7 @@ void AActor::CallTouch(AActor *toucher) IFVIRTUAL(AActor, Touch) { VMValue params[2] = { (DObject*)this, toucher }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } else Touch(toucher); } @@ -3573,7 +3570,7 @@ int AActor::GetMissileDamage (int mask, int add) result.IntAt(&amount); - if (GlobalVMStack.Call(DamageFunc, ¶m, 1, &result, 1) < 1) + if (VMCall(DamageFunc, ¶m, 1, &result, 1) < 1) { // No results return 0; } @@ -3638,7 +3635,7 @@ bool AActor::CallSlam(AActor *thing) VMReturn ret; int retval; ret.IntAt(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return !!retval; } @@ -3656,7 +3653,7 @@ int AActor::SpecialMissileHit (AActor *victim) VMReturn ret; int retval; ret.IntAt(&retval); - GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + VMCall(func, params, 2, &ret, 1); return retval; } else return -1; @@ -3716,7 +3713,7 @@ int AActor::AbsorbDamage(int damage, FName dmgtype) IFVIRTUALPTR(item, AInventory, AbsorbDamage) { VMValue params[4] = { item, damage, dmgtype.GetIndex(), &damage }; - GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr); + VMCall(func, params, 4, nullptr, 0); } } return damage; @@ -3736,7 +3733,7 @@ void AActor::AlterWeaponSprite(visstyle_t *vis) IFVIRTUALPTR(items[i], AInventory, AlterWeaponSprite) { VMValue params[3] = { items[i], vis, &changed }; - GlobalVMStack.Call(func, params, 3, nullptr, 0, nullptr); + VMCall(func, params, 3, nullptr, 0); } } } @@ -3891,7 +3888,7 @@ PClassActor *AActor::GetBloodType(int type) const VMValue params[] = { (DObject*)this, type }; PClassActor *res; VMReturn ret((void**)&res); - GlobalVMStack.Call(func, params, countof(params), &ret, 1); + VMCall(func, params, countof(params), &ret, 1); return res; } return nullptr; @@ -4051,7 +4048,7 @@ void AActor::Tick () IFVIRTUALPTR(item, AInventory, DoEffect) { VMValue params[1] = { item }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } item = item->Inventory; } @@ -5139,7 +5136,7 @@ void AActor::CallBeginPlay() { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } else BeginPlay(); } @@ -5230,7 +5227,7 @@ void AActor::CallActivate(AActor *activator) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)this, (DObject*)activator }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } else Activate(activator); } @@ -5276,7 +5273,7 @@ void AActor::CallDeactivate(AActor *activator) { // Without the type cast this picks the 'void *' assignment... VMValue params[2] = { (DObject*)this, (DObject*)activator }; - GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + VMCall(func, params, 2, nullptr, 0); } else Deactivate(activator); } @@ -5582,7 +5579,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) IFVIRTUALPTR(p->mo, APlayerPawn, OnRespawn) { VMValue param = p->mo; - GlobalVMStack.Call(func, ¶m, 1, nullptr, 0); + VMCall(func, ¶m, 1, nullptr, 0); } } @@ -7455,7 +7452,7 @@ int AActor::CallDoSpecialDamage(AActor *target, int damage, FName damagetype) VMReturn ret; int retval; ret.IntAt(&retval); - GlobalVMStack.Call(func, params, 4, &ret, 1, nullptr); + VMCall(func, params, 4, &ret, 1); return retval; } else return DoSpecialDamage(target, damage, damagetype); @@ -7520,7 +7517,7 @@ int AActor::CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, VMReturn ret; int retval; ret.IntAt(&retval); - GlobalVMStack.Call(func, params, 5, &ret, 1, nullptr); + VMCall(func, params, 5, &ret, 1); return retval; } else return TakeSpecialDamage(inflictor, source, damage, damagetype); @@ -7664,7 +7661,7 @@ int AActor::GetGibHealth() const VMValue params[] = { (DObject*)this }; int h; VMReturn ret(&h); - GlobalVMStack.Call(func, params, 1, &ret, 1); + VMCall(func, params, 1, &ret, 1); return h; } return -SpawnHealth(); @@ -7800,7 +7797,7 @@ int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive) IFVIRTUALPTR(inv, AInventory, ModifyDamage) { VMValue params[5] = { (DObject*)inv, damage, int(damagetype), &damage, passive }; - GlobalVMStack.Call(func, params, 5, nullptr, 0, nullptr); + VMCall(func, params, 5, nullptr, 0); } inv = inv->Inventory; } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 959dbf220..12c158c94 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -31,6 +31,7 @@ #include "v_text.h" #include "cmdlib.h" #include "g_levellocals.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index b64478c77..f84afb1ff 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -36,7 +36,7 @@ #include "r_sky.h" #include "r_data/colormaps.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" // [RH] @@ -1514,7 +1514,7 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) VMReturn ret; int didit; ret.IntAt(&didit); - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + VMCall(func, params, 3, &ret, 1); if (didit) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index e91de462a..08cb7123c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -79,6 +79,7 @@ #include "edata.h" #endif #include "events.h" +#include "types.h" #include "fragglescript/t_fs.h" diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 04cb9c9ea..b4c69d3fe 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -24,6 +24,7 @@ #include "r_utility.h" #include "b_bot.h" #include "p_spec.h" +#include "vm.h" // State. #include "r_state.h" diff --git a/src/p_spec.cpp b/src/p_spec.cpp index fcfd0ddf4..43c094e25 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -76,6 +76,7 @@ #ifndef NO_EDATA #include "edata.h" #endif +#include "vm.h" // State. #include "r_state.h" diff --git a/src/p_states.cpp b/src/p_states.cpp index fae4e13df..c358ceed5 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -41,6 +41,7 @@ #include "v_text.h" #include "thingdef.h" #include "r_state.h" +#include "vm.h" // stores indices for symbolic state labels for some old-style DECORATE functions. diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 748e25ca3..6fe06ed0f 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -37,6 +37,7 @@ #include "p_tags.h" #include "c_dispatch.h" #include "g_levellocals.h" +#include "vm.h" FTagManager tagManager; diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index b34b4de1d..a56e4e790 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -39,6 +39,7 @@ #include "r_utility.h" #include "p_spec.h" #include "g_levellocals.h" +#include "vm.h" #define FUDGEFACTOR 10 diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index b044b3066..717747a8a 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -47,6 +47,7 @@ #include "p_local.h" #include "templates.h" #include "actor.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/p_things.cpp b/src/p_things.cpp index ac105f4ee..94dc1df1d 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -53,6 +53,7 @@ #include "actorptrselect.h" #include "g_levellocals.h" #include "actorinlines.h" +#include "vm.h" // Set of spawnable things for the Thing_Spawn and Thing_Projectile specials. FClassMap SpawnableThings; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 1506059ea..81b1d0a90 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -50,6 +50,7 @@ #include "p_terrain.h" #include "g_levellocals.h" #include "info.h" +#include "vm.h" //=========================================================================== // diff --git a/src/p_user.cpp b/src/p_user.cpp index f1f1b31f2..b0cce58ab 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -58,7 +58,7 @@ #include "p_blockmap.h" #include "a_morph.h" #include "p_spec.h" -#include "virtual.h" +#include "vm.h" #include "g_levellocals.h" #include "actorinlines.h" #include "r_data/r_translate.h" @@ -1505,7 +1505,7 @@ void APlayerPawn::PlayIdle () IFVIRTUAL(APlayerPawn, PlayIdle) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -1514,7 +1514,7 @@ void APlayerPawn::PlayRunning () IFVIRTUAL(APlayerPawn, PlayRunning) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -1523,7 +1523,7 @@ void APlayerPawn::PlayAttacking () IFVIRTUAL(APlayerPawn, PlayAttacking) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -1532,7 +1532,7 @@ void APlayerPawn::PlayAttacking2 () IFVIRTUAL(APlayerPawn, PlayAttacking2) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } @@ -1630,7 +1630,7 @@ void APlayerPawn::MorphPlayerThink () IFVIRTUAL(APlayerPawn, MorphPlayerThink) { VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } } diff --git a/src/portal.cpp b/src/portal.cpp index acf6e022d..9926f289e 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -52,6 +52,7 @@ #include "p_checkposition.h" #include "math/cmath.h" #include "g_levellocals.h" +#include "vm.h" // simulation recurions maximum CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index adcbc93fd..3c61ec4ac 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -50,6 +50,7 @@ #include "d_player.h" #include "r_data/sprites.h" #include "r_state.h" +#include "vm.h" #include "gi.h" #include "stats.h" diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index 7a5927be6..17abea01e 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -14,6 +14,7 @@ #include "r_data/sprites.h" #include "r_data/voxels.h" #include "textures/textures.h" +#include "vm.h" void gl_InitModels(); diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 71cb943f8..8d4652d2b 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -30,6 +30,7 @@ #include "serializer.h" #include "d_player.h" #include "g_levellocals.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/s_sound.cpp b/src/s_sound.cpp index a767fdcaa..75f6a68a8 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -54,7 +54,7 @@ #include "d_player.h" #include "r_state.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ @@ -487,7 +487,7 @@ void S_PrecacheLevel () { // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { actor }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + VMCall(func, params, 1, nullptr, 0); } else { diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 7d731eb5f..0c47493ea 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6620,7 +6620,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) ob.Free(build); ExpEmit meta(build, REGT_POINTER); build->Emit(OP_CLSS, meta.RegNum, ob.RegNum); - build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LP, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return meta; } @@ -6878,7 +6878,7 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) if (offsetreg == -1) offsetreg = build->GetConstantInt(0); auto op = membervar->Type->GetLoadOp(); if (op == OP_LO) - op = OP_LOS; + op = OP_LP; build->Emit(op, loc.RegNum, build->FramePointer.RegNum, offsetreg); } else @@ -9355,7 +9355,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) op.Free(build); } ExpEmit to(build, REGT_POINTER); - build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); return to; } @@ -9427,7 +9427,7 @@ ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) build->Emit(OP_LKP, to.RegNum, op.RegNum); op = to; } - build->Emit(OP_LOS, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + build->Emit(OP_LP, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); return to; } diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 35831c958..1f6c8baca 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -46,6 +46,8 @@ #include "actor.h" #include "vmbuilder.h" #include "scopebarrier.h" +#include "types.h" +#include "vmintern.h" #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; diff --git a/src/scripting/backend/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp index 0152c6520..2262af154 100644 --- a/src/scripting/backend/dynarrays.cpp +++ b/src/scripting/backend/dynarrays.cpp @@ -39,7 +39,9 @@ #include "tarray.h" #include "dobject.h" -#include "thingdef.h" +#include "vm.h" +#include "types.h" + // We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them. // Dynamic arrays cannot hold structs because for every type there'd need to be an internal implementation which is impossible. diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index f227e0240..c42632318 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -1,5 +1,7 @@ #include "dobject.h" #include "scopebarrier.h" +#include "types.h" +#include "vmintern.h" // Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found. diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index d8af3204d..13f9ecb27 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -35,8 +35,9 @@ #include "codegen.h" #include "info.h" #include "m_argv.h" -#include "thingdef.h" +//#include "thingdef.h" #include "doomerrors.h" +#include "vmintern.h" struct VMRemap { diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index ea5213b66..d33688276 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -2,6 +2,7 @@ #define VMUTIL_H #include "dobject.h" +#include "vmintern.h" class VMFunctionBuilder; class FxExpression; diff --git a/src/scripting/backend/vmdisasm.cpp b/src/scripting/backend/vmdisasm.cpp index 3a37da8e3..be5390bba 100644 --- a/src/scripting/backend/vmdisasm.cpp +++ b/src/scripting/backend/vmdisasm.cpp @@ -34,6 +34,7 @@ #include "dobject.h" #include "c_console.h" #include "templates.h" +#include "vmintern.h" #define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED diff --git a/src/scripting/symbols.cpp b/src/scripting/symbols.cpp index 5fc59f7b0..098ecaaa5 100644 --- a/src/scripting/symbols.cpp +++ b/src/scripting/symbols.cpp @@ -38,6 +38,8 @@ #include "i_system.h" #include "templates.h" #include "serializer.h" +#include "types.h" +#include "vm.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -128,6 +130,80 @@ int PFunction::GetImplicitArgs() return 0; } +/* PField *****************************************************************/ + +IMPLEMENT_CLASS(PField, false, false) + +//========================================================================== +// +// PField - Default Constructor +// +//========================================================================== + +PField::PField() +: PSymbol(NAME_None), Offset(0), Type(nullptr), Flags(0) +{ +} + + +PField::PField(FName name, PType *type, uint32_t flags, size_t offset, int bitvalue) + : PSymbol(name), Offset(offset), Type(type), Flags(flags) +{ + if (bitvalue != 0) + { + BitValue = 0; + unsigned val = bitvalue; + while ((val >>= 1)) BitValue++; + + if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size) + { + // map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values. +#ifndef __BIG_ENDIAN__ + Offset += BitValue / 8; +#else + Offset += type->Size - 1 - BitValue / 8; +#endif + BitValue &= 7; + Type = TypeBool; + } + else + { + // Just abort. Bit fields should only be defined internally. + I_Error("Trying to create an invalid bit field element: %s", name.GetChars()); + } + } + else BitValue = -1; +} + +VersionInfo PField::GetVersion() +{ + VersionInfo Highest = { 0,0,0 }; + if (!(Flags & VARF_Deprecated)) Highest = mVersion; + if (Type->mVersion > Highest) Highest = Type->mVersion; + return Highest; +} + +/* PProperty *****************************************************************/ + +IMPLEMENT_CLASS(PProperty, false, false) + +//========================================================================== +// +// PField - Default Constructor +// +//========================================================================== + +PProperty::PProperty() + : PSymbol(NAME_None) +{ +} + +PProperty::PProperty(FName name, TArray &fields) + : PSymbol(name) +{ + Variables = std::move(fields); +} + //========================================================================== // // diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 649e5584a..2268bd5ea 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -274,5 +274,4 @@ struct FNamespaceManager }; extern FNamespaceManager Namespaces; - - +void RemoveUnusedSymbols(); diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 14fd21886..bf585077f 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -59,7 +59,7 @@ #include "a_weapons.h" #include "p_conversation.h" #include "v_text.h" -#include "thingdef.h" +//#include "thingdef.h" #include "backend/codegen.h" #include "a_sharedglobal.h" #include "backend/vmbuilder.h" diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index d727623b4..8019a5a41 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -6,6 +6,7 @@ #include "s_sound.h" #include "sc_man.h" #include "cmdlib.h" +#include "vm.h" class FScanner; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 5bbeb9296..3c2b4e3f1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -61,6 +61,8 @@ #include "serializer.h" #include "wi_stuff.h" #include "a_dynlight.h" +#include "vm.h" +#include "types.h" static TArray properties; static TArray AFTable; diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 0084c319c..374d8a524 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -70,6 +70,7 @@ #include "a_keys.h" #include "g_levellocals.h" #include "d_player.h" +#include "types.h" //========================================================================== // diff --git a/src/scripting/types.cpp b/src/scripting/types.cpp new file mode 100644 index 000000000..b445ad884 --- /dev/null +++ b/src/scripting/types.cpp @@ -0,0 +1,2689 @@ +/* +** types.cpp +** Implements the VM type hierarchy +** +**--------------------------------------------------------------------------- +** Copyright 2008-2016 Randy Heit +** Copyright 2016-2017 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "vmintern.h" +#include "s_sound.h" +#include "dthinker.h" +#include "types.h" + + +FTypeTable TypeTable; + +PErrorType *TypeError; +PErrorType *TypeAuto; +PVoidType *TypeVoid; +PInt *TypeSInt8, *TypeUInt8; +PInt *TypeSInt16, *TypeUInt16; +PInt *TypeSInt32, *TypeUInt32; +PBool *TypeBool; +PFloat *TypeFloat32, *TypeFloat64; +PString *TypeString; +PName *TypeName; +PSound *TypeSound; +PColor *TypeColor; +PTextureID *TypeTextureID; +PSpriteID *TypeSpriteID; +PStatePointer *TypeState; +PPointer *TypeFont; +PStateLabel *TypeStateLabel; +PStruct *TypeVector2; +PStruct *TypeVector3; +PStruct *TypeColorStruct; +PStruct *TypeStringStruct; +PPointer *TypeNullPtr; +PPointer *TypeVoidPtr; + + +// CODE -------------------------------------------------------------------- + +IMPLEMENT_CLASS(PErrorType, false, false) +IMPLEMENT_CLASS(PVoidType, false, false) + +void DumpTypeTable() +{ + int used = 0; + int min = INT_MAX; + int max = 0; + int all = 0; + int lens[10] = {0}; + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + int len = 0; + Printf("%4zu:", i); + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr; ty = ty->HashNext) + { + Printf(" -> %s", ty->DescriptiveName()); + len++; + all++; + } + if (len != 0) + { + used++; + if (len < min) + min = len; + if (len > max) + max = len; + } + if (len < (int)countof(lens)) + { + lens[len]++; + } + Printf("\n"); + } + Printf("Used buckets: %d/%lu (%.2f%%) for %d entries\n", used, countof(TypeTable.TypeHash), double(used)/countof(TypeTable.TypeHash)*100, all); + Printf("Min bucket size: %d\n", min); + Printf("Max bucket size: %d\n", max); + Printf("Avg bucket size: %.2f\n", double(all) / used); + int j,k; + for (k = countof(lens)-1; k > 0; --k) + if (lens[k]) + break; + for (j = 0; j <= k; ++j) + Printf("Buckets of len %d: %d (%.2f%%)\n", j, lens[j], j!=0?double(lens[j])/used*100:-1.0); +} + +/* PType ******************************************************************/ + +IMPLEMENT_CLASS(PType, true, false) + +//========================================================================== +// +// PType Parameterized Constructor +// +//========================================================================== + +PType::PType(unsigned int size, unsigned int align) +: Size(size), Align(align), HashNext(nullptr) +{ + mDescriptiveName = "Type"; + loadOp = OP_NOP; + storeOp = OP_NOP; + moveOp = OP_NOP; + RegType = REGT_NIL; + RegCount = 1; +} + +//========================================================================== +// +// PType Destructor +// +//========================================================================== + +PType::~PType() +{ +} + +//========================================================================== +// +// PType :: WriteValue +// +//========================================================================== + +void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + assert(0 && "Cannot write value for this type"); +} + +//========================================================================== +// +// PType :: ReadValue +// +//========================================================================== + +bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + assert(0 && "Cannot read value for this type"); + return false; +} + +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetDefaultValue(void *base, unsigned offset, TArray *stroffs) +{ +} + +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) +{ +} + +void PType::SetPointerArray(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 +// +//========================================================================== + +void PType::SetValue(void *addr, int val) +{ + assert(0 && "Cannot set int value for this type"); +} + +void PType::SetValue(void *addr, double val) +{ + assert(0 && "Cannot set float value for this type"); +} + +//========================================================================== +// +// PType :: GetValue +// +//========================================================================== + +int PType::GetValueInt(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + +double PType::GetValueFloat(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + +//========================================================================== +// +// PType :: IsMatch +// +//========================================================================== + +bool PType::IsMatch(intptr_t id1, intptr_t id2) const +{ + return false; +} + +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = 0; + id2 = 0; +} + +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +const char *PType::DescriptiveName() const +{ + return mDescriptiveName.GetChars(); +} + +//========================================================================== +// +// PType :: StaticInit STATIC +// +//========================================================================== + +void PType::StaticInit() +{ + // Create types and add them type the type table. + TypeTable.AddType(TypeError = new PErrorType); + TypeTable.AddType(TypeAuto = new PErrorType(2)); + TypeTable.AddType(TypeVoid = new PVoidType); + TypeTable.AddType(TypeSInt8 = new PInt(1, false)); + TypeTable.AddType(TypeUInt8 = new PInt(1, true)); + TypeTable.AddType(TypeSInt16 = new PInt(2, false)); + TypeTable.AddType(TypeUInt16 = new PInt(2, true)); + TypeTable.AddType(TypeSInt32 = new PInt(4, false)); + TypeTable.AddType(TypeUInt32 = new PInt(4, true)); + TypeTable.AddType(TypeBool = new PBool); + TypeTable.AddType(TypeFloat32 = new PFloat(4)); + TypeTable.AddType(TypeFloat64 = new PFloat(8)); + TypeTable.AddType(TypeString = new PString); + TypeTable.AddType(TypeName = new PName); + TypeTable.AddType(TypeSound = new PSound); + TypeTable.AddType(TypeColor = new PColor); + TypeTable.AddType(TypeState = new PStatePointer); + TypeTable.AddType(TypeStateLabel = new PStateLabel); + TypeTable.AddType(TypeNullPtr = new PPointer); + TypeTable.AddType(TypeSpriteID = new PSpriteID); + TypeTable.AddType(TypeTextureID = new PTextureID); + + TypeVoidPtr = NewPointer(TypeVoid, false); + TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. + TypeStringStruct = NewStruct("Stringstruct", nullptr, true); + TypeFont = NewPointer(NewStruct("Font", nullptr, true)); +#ifdef __BIG_ENDIAN__ + TypeColorStruct->AddField(NAME_a, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_b, TypeUInt8); +#else + TypeColorStruct->AddField(NAME_b, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_a, TypeUInt8); +#endif + + TypeVector2 = new PStruct(NAME_Vector2, nullptr); + TypeVector2->AddField(NAME_X, TypeFloat64); + TypeVector2->AddField(NAME_Y, TypeFloat64); + TypeTable.AddType(TypeVector2); + TypeVector2->loadOp = OP_LV2; + TypeVector2->storeOp = OP_SV2; + TypeVector2->moveOp = OP_MOVEV2; + TypeVector2->RegType = REGT_FLOAT; + TypeVector2->RegCount = 2; + + TypeVector3 = new PStruct(NAME_Vector3, nullptr); + TypeVector3->AddField(NAME_X, TypeFloat64); + TypeVector3->AddField(NAME_Y, TypeFloat64); + TypeVector3->AddField(NAME_Z, TypeFloat64); + // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient + TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeVector3); + TypeVector3->loadOp = OP_LV3; + TypeVector3->storeOp = OP_SV3; + TypeVector3->moveOp = OP_MOVEV3; + TypeVector3->RegType = REGT_FLOAT; + TypeVector3->RegCount = 3; + + + + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Short, TypeSInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uShort, TypeUInt16)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Int, TypeSInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_uInt, TypeUInt32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Bool, TypeBool)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Double, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float32, TypeFloat32)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Float64, TypeFloat64)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_String, TypeString)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Name, TypeName)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2)); + Namespaces.GlobalNamespace->Symbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3)); +} + + +/* PBasicType *************************************************************/ + +IMPLEMENT_CLASS(PBasicType, true, false) + +//========================================================================== +// +// PBasicType Default Constructor +// +//========================================================================== + +PBasicType::PBasicType() +{ +} + +//========================================================================== +// +// PBasicType Parameterized Constructor +// +//========================================================================== + +PBasicType::PBasicType(unsigned int size, unsigned int align) +: PType(size, align) +{ + mDescriptiveName = "BasicType"; +} + +/* PCompoundType **********************************************************/ + +IMPLEMENT_CLASS(PCompoundType, true, false) + +/* PContainerType *************************************************************/ + +IMPLEMENT_CLASS(PContainerType, true, false) + +//========================================================================== +// +// PContainerType :: IsMatch +// +//========================================================================== + +bool PContainerType::IsMatch(intptr_t id1, intptr_t id2) const +{ + const DObject *outer = (const DObject *)id1; + FName name = (ENamedName)(intptr_t)id2; + + return Outer == outer && TypeName == name; +} + +//========================================================================== +// +// PContainerType :: GetTypeIDs +// +//========================================================================== + +void PContainerType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)Outer; + id2 = TypeName; +} + +/* PInt *******************************************************************/ + +IMPLEMENT_CLASS(PInt, false, false) + +//========================================================================== +// +// PInt Default Constructor +// +//========================================================================== + +PInt::PInt() +: PBasicType(4, 4), Unsigned(false), IntCompatible(true) +{ + mDescriptiveName = "SInt32"; + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); + SetOps(); +} + +//========================================================================== +// +// PInt Parameterized Constructor +// +//========================================================================== + +PInt::PInt(unsigned int size, bool unsign, bool compatible) +: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) +{ + mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); + + MemberOnly = (size < 4); + if (!unsign) + { + int maxval = (1u << ((8 * size) - 1)) - 1; // compute as unsigned to prevent overflow before -1 + int minval = -maxval - 1; + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, minval)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, maxval)); + } + else + { + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); + Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << ((8 * size) - 1)))); + } + SetOps(); +} + +void PInt::SetOps() +{ + moveOp = OP_MOVE; + RegType = REGT_INT; + if (Size == 4) + { + storeOp = OP_SW; + loadOp = OP_LW; + } + else if (Size == 1) + { + storeOp = OP_SB; + loadOp = Unsigned ? OP_LBU : OP_LB; + } + else if (Size == 2) + { + storeOp = OP_SH; + loadOp = Unsigned ? OP_LHU : OP_LH; + } + else + { + assert(0 && "Unhandled integer size"); + storeOp = OP_NOP; + } +} + +//========================================================================== +// +// PInt :: WriteValue +// +//========================================================================== + +void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (Size == 8 && Unsigned) + { + // this is a special case that cannot be represented by an int64_t. + uint64_t val = *(uint64_t*)addr; + ar(key, val); + } + else + { + int64_t val; + switch (Size) + { + case 1: + val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr; + break; + + case 2: + val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr; + break; + + case 4: + val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr; + break; + + case 8: + val = *(int64_t*)addr; + break; + + default: + return; // something invalid + } + ar(key, val); + } +} + +//========================================================================== +// +// PInt :: ReadValue +// +//========================================================================== + +bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + NumericValue val; + + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval; + + // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both. + switch (Size) + { + case 1: + *(uint8_t*)addr = (uint8_t)val.signedval; + break; + + case 2: + *(uint16_t*)addr = (uint16_t)val.signedval; + break; + + case 4: + *(uint32_t*)addr = (uint32_t)val.signedval; + break; + + case 8: + *(uint64_t*)addr = (uint64_t)val.signedval; + break; + + default: + return false; // something invalid + } + + return true; +} + +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PInt::SetValue(void *addr, int val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(int *)addr = val; + } + else if (Size == 1) + { + *(uint8_t *)addr = val; + } + else if (Size == 2) + { + *(uint16_t *)addr = val; + } + else if (Size == 8) + { + *(uint64_t *)addr = val; + } + else + { + assert(0 && "Unhandled integer size"); + } +} + +void PInt::SetValue(void *addr, double val) +{ + SetValue(addr, (int)val); +} + +//========================================================================== +// +// PInt :: GetValueInt +// +//========================================================================== + +int PInt::GetValueInt(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(int *)addr; + } + else if (Size == 1) + { + return Unsigned ? *(uint8_t *)addr : *(int8_t *)addr; + } + else if (Size == 2) + { + return Unsigned ? *(uint16_t *)addr : *(int16_t *)addr; + } + else if (Size == 8) + { // truncated output + return (int)*(uint64_t *)addr; + } + else + { + assert(0 && "Unhandled integer size"); + return 0; + } +} + +//========================================================================== +// +// PInt :: GetValueFloat +// +//========================================================================== + +double PInt::GetValueFloat(void *addr) const +{ + return GetValueInt(addr); +} + +//========================================================================== +// +// PInt :: GetStoreOp +// +//========================================================================== + +/* PBool ******************************************************************/ + +IMPLEMENT_CLASS(PBool, false, false) + +//========================================================================== +// +// PInt :: SetValue +// +//========================================================================== + +void PBool::SetValue(void *addr, int val) +{ + *(bool*)addr = !!val; +} + +void PBool::SetValue(void *addr, double val) +{ + *(bool*)addr = val != 0.; +} + +int PBool::GetValueInt(void *addr) const +{ + return *(bool *)addr; +} + +double PBool::GetValueFloat(void *addr) const +{ + return *(bool *)addr; +} + +//========================================================================== +// +// PBool Default Constructor +// +//========================================================================== + +PBool::PBool() +: PInt(sizeof(bool), true) +{ + mDescriptiveName = "Bool"; + MemberOnly = false; +} + +/* PFloat *****************************************************************/ + +IMPLEMENT_CLASS(PFloat, false, false) + +//========================================================================== +// +// PFloat Default Constructor +// +//========================================================================== + +PFloat::PFloat() +: PBasicType(8, 8) +{ + mDescriptiveName = "Float"; + SetDoubleSymbols(); + SetOps(); +} + +//========================================================================== +// +// PFloat Parameterized Constructor +// +//========================================================================== + +PFloat::PFloat(unsigned int size) +: PBasicType(size, size) +{ + mDescriptiveName.Format("Float%d", size); + if (size == 8) + { +#ifdef __i386__ + // According to System V i386 ABI alignment of double type is 4 + // GCC and Clang for 32-bit Intel targets follow this requirement + // However GCC has -malign-double option to enable 8-byte alignment + // So calculation of the actual alignment is needed + struct AlignmentCheck { uint8_t i; double d; }; + Align = static_cast(offsetof(AlignmentCheck, d)); +#endif // __i386__ + + SetDoubleSymbols(); + } + else + { + assert(size == 4); + MemberOnly = true; + SetSingleSymbols(); + } + SetOps(); +} + +//========================================================================== +// +// PFloat :: SetDoubleSymbols +// +// Setup constant values for 64-bit floats. +// +//========================================================================== + +void PFloat::SetDoubleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, DBL_MIN }, + { NAME_Max, DBL_MAX }, + { NAME_Epsilon, DBL_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, DBL_DIG }, + { NAME_Min_Exp, DBL_MIN_EXP }, + { NAME_Max_Exp, DBL_MAX_EXP }, + { NAME_Mant_Dig, DBL_MANT_DIG }, + { NAME_Min_10_Exp, DBL_MIN_10_EXP }, + { NAME_Max_10_Exp, DBL_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSingleSymbols +// +// Setup constant values for 32-bit floats. +// +//========================================================================== + +void PFloat::SetSingleSymbols() +{ + static const SymbolInitF symf[] = + { + { NAME_Min_Normal, FLT_MIN }, + { NAME_Max, FLT_MAX }, + { NAME_Epsilon, FLT_EPSILON }, + { NAME_NaN, std::numeric_limits::quiet_NaN() }, + { NAME_Infinity, std::numeric_limits::infinity() }, + { NAME_Min_Denormal, std::numeric_limits::denorm_min() } + }; + static const SymbolInitI symi[] = + { + { NAME_Dig, FLT_DIG }, + { NAME_Min_Exp, FLT_MIN_EXP }, + { NAME_Max_Exp, FLT_MAX_EXP }, + { NAME_Mant_Dig, FLT_MANT_DIG }, + { NAME_Min_10_Exp, FLT_MIN_10_EXP }, + { NAME_Max_10_Exp, FLT_MAX_10_EXP } + }; + SetSymbols(symf, countof(symf)); + SetSymbols(symi, countof(symi)); +} + +//========================================================================== +// +// PFloat :: SetSymbols +// +//========================================================================== + +void PFloat::SetSymbols(const PFloat::SymbolInitF *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } +} + +void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + Symbols.AddSymbol(new PSymbolConstNumeric(sym[i].Name, this, sym[i].Value)); + } +} + +//========================================================================== +// +// PFloat :: WriteValue +// +//========================================================================== + +void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (Size == 8) + { + ar(key, *(double*)addr); + } + else + { + ar(key, *(float*)addr); + } +} + +//========================================================================== +// +// PFloat :: ReadValue +// +//========================================================================== + +bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + NumericValue val; + + ar(key, val); + if (val.type == NumericValue::NM_invalid) return false; // not found or usable + else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval; + else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval; + + if (Size == 8) + { + *(double*)addr = val.floatval; + } + else + { + *(float*)addr = (float)val.floatval; + } + return true; +} + +//========================================================================== +// +// PFloat :: SetValue +// +//========================================================================== + +void PFloat::SetValue(void *addr, int val) +{ + return SetValue(addr, (double)val); +} + +void PFloat::SetValue(void *addr, double val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + *(float *)addr = (float)val; + } + else + { + assert(Size == 8); + *(double *)addr = val; + } +} + +//========================================================================== +// +// PFloat :: GetValueInt +// +//========================================================================== + +int PFloat::GetValueInt(void *addr) const +{ + return xs_ToInt(GetValueFloat(addr)); +} + +//========================================================================== +// +// PFloat :: GetValueFloat +// +//========================================================================== + +double PFloat::GetValueFloat(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + if (Size == 4) + { + return *(float *)addr; + } + else + { + assert(Size == 8); + return *(double *)addr; + } +} + +//========================================================================== +// +// PFloat :: GetStoreOp +// +//========================================================================== + +void PFloat::SetOps() +{ + if (Size == 4) + { + storeOp = OP_SSP; + loadOp = OP_LSP; + } + else + { + assert(Size == 8); + storeOp = OP_SDP; + loadOp = OP_LDP; + } + moveOp = OP_MOVEF; + RegType = REGT_FLOAT; +} + +/* PString ****************************************************************/ + +IMPLEMENT_CLASS(PString, false, false) + +//========================================================================== +// +// PString Default Constructor +// +//========================================================================== + +PString::PString() +: PBasicType(sizeof(FString), alignof(FString)) +{ + mDescriptiveName = "String"; + storeOp = OP_SS; + loadOp = OP_LS; + moveOp = OP_MOVES; + RegType = REGT_STRING; + +} + +//========================================================================== +// +// PString :: WriteValue +// +//========================================================================== + +void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + ar(key, *(FString*)addr); +} + +//========================================================================== +// +// PString :: ReadValue +// +//========================================================================== + +bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FString*)addr = cptr; + return true; + } +} + +//========================================================================== +// +// PString :: SetDefaultValue +// +//========================================================================== + +void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + if (base != nullptr) new((uint8_t *)base + offset) FString; + if (special != nullptr) + { + special->Push(std::make_pair(this, offset)); + } +} + +//========================================================================== +// +// PString :: InitializeValue +// +//========================================================================== + +void PString::InitializeValue(void *addr, const void *def) const +{ + if (def != nullptr) + { + new(addr) FString(*(FString *)def); + } + else + { + new(addr) FString; + } +} + +//========================================================================== +// +// PString :: DestroyValue +// +//========================================================================== + +void PString::DestroyValue(void *addr) const +{ + ((FString *)addr)->~FString(); +} + +/* PName ******************************************************************/ + +IMPLEMENT_CLASS(PName, false, false) + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PName::PName() +: PInt(sizeof(FName), true, false) +{ + mDescriptiveName = "Name"; + assert(sizeof(FName) == alignof(FName)); +} + +//========================================================================== +// +// PName :: WriteValue +// +//========================================================================== + +void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + const char *cptr = ((const FName*)addr)->GetChars(); + ar.StringPtr(key, cptr); +} + +//========================================================================== +// +// PName :: ReadValue +// +//========================================================================== + +bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FName*)addr = FName(cptr); + return true; + } +} + +/* PSpriteID ******************************************************************/ + +IMPLEMENT_CLASS(PSpriteID, false, false) + +//========================================================================== +// +// PName Default Constructor +// +//========================================================================== + +PSpriteID::PSpriteID() + : PInt(sizeof(int), true, true) +{ + mDescriptiveName = "SpriteID"; +} + +//========================================================================== +// +// PName :: WriteValue +// +//========================================================================== + +void PSpriteID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + int32_t val = *(int*)addr; + ar.Sprite(key, val, nullptr); +} + +//========================================================================== +// +// PName :: ReadValue +// +//========================================================================== + +bool PSpriteID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + int32_t val; + ar.Sprite(key, val, nullptr); + *(int*)addr = val; + return true; +} + +/* PTextureID ******************************************************************/ + +IMPLEMENT_CLASS(PTextureID, false, false) + +//========================================================================== +// +// PTextureID Default Constructor +// +//========================================================================== + +PTextureID::PTextureID() + : PInt(sizeof(FTextureID), true, false) +{ + mDescriptiveName = "TextureID"; + assert(sizeof(FTextureID) == alignof(FTextureID)); +} + +//========================================================================== +// +// PTextureID :: WriteValue +// +//========================================================================== + +void PTextureID::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + FTextureID val = *(FTextureID*)addr; + ar(key, val); +} + +//========================================================================== +// +// PTextureID :: ReadValue +// +//========================================================================== + +bool PTextureID::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + FTextureID val; + ar(key, val); + *(FTextureID*)addr = val; + return true; +} + +/* PSound *****************************************************************/ + +IMPLEMENT_CLASS(PSound, false, false) + +//========================================================================== +// +// PSound Default Constructor +// +//========================================================================== + +PSound::PSound() +: PInt(sizeof(FSoundID), true) +{ + mDescriptiveName = "Sound"; + assert(sizeof(FSoundID) == alignof(FSoundID)); +} + +//========================================================================== +// +// PSound :: WriteValue +// +//========================================================================== + +void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + const char *cptr = *(const FSoundID *)addr; + ar.StringPtr(key, cptr); +} + +//========================================================================== +// +// PSound :: ReadValue +// +//========================================================================== + +bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + const char *cptr; + ar.StringPtr(key, cptr); + if (cptr == nullptr) + { + return false; + } + else + { + *(FSoundID *)addr = FSoundID(cptr); + return true; + } +} + +/* PColor *****************************************************************/ + +IMPLEMENT_CLASS(PColor, false, false) + +//========================================================================== +// +// PColor Default Constructor +// +//========================================================================== + +PColor::PColor() +: PInt(sizeof(PalEntry), true) +{ + mDescriptiveName = "Color"; + assert(sizeof(PalEntry) == alignof(PalEntry)); +} + +/* PStateLabel *****************************************************************/ + +IMPLEMENT_CLASS(PStateLabel, false, false) + +//========================================================================== +// +// PStateLabel Default Constructor +// +//========================================================================== + +PStateLabel::PStateLabel() + : PInt(sizeof(int), false, false) +{ + mDescriptiveName = "StateLabel"; +} + +/* PPointer ***************************************************************/ + +IMPLEMENT_CLASS(PPointer, false, false) + +//========================================================================== +// +// PPointer - Default Constructor +// +//========================================================================== + +PPointer::PPointer() +: PBasicType(sizeof(void *), alignof(void *)), PointedType(nullptr), IsConst(false) +{ + mDescriptiveName = "NullPointer"; + loadOp = OP_LP; + storeOp = OP_SP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; +} + +//========================================================================== +// +// PPointer - Parameterized Constructor +// +//========================================================================== + +PPointer::PPointer(PType *pointsat, bool isconst) +: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) +{ + if (pointsat != nullptr) + { + mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst ? "readonly " : ""); + mVersion = pointsat->mVersion; + } + else + { + mDescriptiveName = "Pointer"; + mVersion = 0; + } + loadOp = OP_LP; + storeOp = OP_SP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; +} + +//========================================================================== +// +// PPointer :: IsMatch +// +//========================================================================== + +bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0 || id2 == 1); + PType *pointat = (PType *)id1; + + return pointat == PointedType && (!!id2) == IsConst; +} + +//========================================================================== +// +// PPointer :: GetTypeIDs +// +//========================================================================== + +void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)PointedType; + id2 = 0; +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (writer != nullptr) + { + writer(ar, key, addr); + } + else + { + I_Error("Attempt to save pointer to unhandled type %s", PointedType->DescriptiveName()); + } +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (reader != nullptr) + { + return reader(ar, key, addr); + } + return false; +} + +/* PObjectPointer **********************************************************/ + +IMPLEMENT_CLASS(PObjectPointer, false, false) + +//========================================================================== +// +// PPointer :: GetStoreOp +// +//========================================================================== + +PObjectPointer::PObjectPointer(PClass *cls, bool isconst) + : PPointer(cls->VMType, isconst) +{ + loadOp = OP_LO; + // Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them. + if (cls && !cls->IsDescendantOf(RUNTIME_CLASS(DThinker))) storeOp = OP_SO; +} + +//========================================================================== +// +// PPointer :: SetPointer +// +//========================================================================== + +void PObjectPointer::SetPointer(void *base, unsigned offset, TArray *special) +{ + // Add to the list of pointers for this class. + special->Push(offset); +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PObjectPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(DObject **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PObjectPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res; + ::Serialize(ar, key, *(DObject **)addr, nullptr, &res); + return res; +} + +//========================================================================== +// +// NewPointer +// +// Returns a PPointer to an object of the specified type +// +//========================================================================== + +PPointer *NewPointer(PType *type, bool isconst) +{ + auto cp = dyn_cast(type); + if (cp) return NewPointer(cp->Descriptor, isconst); + + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); +} + +PPointer *NewPointer(PClass *cls, bool isconst) +{ + assert(cls->VMType != nullptr); + + auto type = cls->VMType; + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); + if (ptype == nullptr) + { + ptype = new PObjectPointer(cls, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PObjectPointer), (intptr_t)type, isconst ? 1 : 0, bucket); + } + return static_cast(ptype); +} + +/* PStatePointer **********************************************************/ + +IMPLEMENT_CLASS(PStatePointer, false, false) + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +{ + mDescriptiveName = "Pointer"; + PointedType = NewStruct(NAME_State, nullptr, true); + IsConst = true; +} + +//========================================================================== +// +// PStatePointer :: WriteValue +// +//========================================================================== + +void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(FState **)addr); +} + +//========================================================================== +// +// PStatePointer :: ReadValue +// +//========================================================================== + +bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res = false; + ::Serialize(ar, key, *(FState **)addr, nullptr, &res); + return res; +} + + + +/* PClassPointer **********************************************************/ + +IMPLEMENT_CLASS(PClassPointer,false, false) + +//========================================================================== +// +// PClassPointer - Parameterized Constructor +// +//========================================================================== + +PClassPointer::PClassPointer(PClass *restrict) +: PPointer(restrict->VMType), ClassRestriction(restrict) +{ + if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); + else mDescriptiveName = "ClassPointer"; + loadOp = OP_LP; + storeOp = OP_SP; + mVersion = restrict->VMType->mVersion; +} + +//========================================================================== +// +// PPointer :: WriteValue +// +//========================================================================== + +void PClassPointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(PClass **)addr); +} + +//========================================================================== +// +// PPointer :: ReadValue +// +//========================================================================== + +bool PClassPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + ::Serialize(ar, key, *(PClass **)addr, (PClass**)nullptr); + return false; +} + +//========================================================================== +// +// PClassPointer - isCompatible +// +//========================================================================== + +bool PClassPointer::isCompatible(PType *type) +{ + auto other = dyn_cast(type); + return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction)); +} + +//========================================================================== +// +// PClassPointer :: SetPointer +// +//========================================================================== + +void PClassPointer::SetPointer(void *base, unsigned offset, TArray *special) +{ +} + +//========================================================================== +// +// PClassPointer :: IsMatch +// +//========================================================================== + +bool PClassPointer::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PClass *classat = (const PClass *)id2; + return classat == ClassRestriction; +} + +//========================================================================== +// +// PClassPointer :: GetTypeIDs +// +//========================================================================== + +void PClassPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = 0; + id2 = (intptr_t)ClassRestriction; +} + +//========================================================================== +// +// NewClassPointer +// +// Returns a PClassPointer for the restricted type. +// +//========================================================================== + +PClassPointer *NewClassPointer(PClass *restrict) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, &bucket); + if (ptype == nullptr) + { + ptype = new PClassPointer(restrict); + TypeTable.AddType(ptype, RUNTIME_CLASS(PClassPointer), 0, (intptr_t)restrict, bucket); + } + return static_cast(ptype); +} + +/* PEnum ******************************************************************/ + +IMPLEMENT_CLASS(PEnum, false, false) + +//========================================================================== +// +// PEnum - Default Constructor +// +//========================================================================== + +PEnum::PEnum() +: PInt(4, false) +{ + mDescriptiveName = "Enum"; +} + +//========================================================================== +// +// PEnum - Parameterized Constructor +// +//========================================================================== + +PEnum::PEnum(FName name, PTypeBase *outer) +: PInt(4, false) +{ + EnumName = name; + Outer = outer; + mDescriptiveName.Format("Enum<%s>", name.GetChars()); +} + +//========================================================================== +// +// NewEnum +// +// Returns a PEnum for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +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 == nullptr) + { + etype = new PEnum(name, outer); + TypeTable.AddType(etype, RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(etype); +} + +/* PArray *****************************************************************/ + +IMPLEMENT_CLASS(PArray, false, false) + +//========================================================================== +// +// PArray - Default Constructor +// +//========================================================================== + +PArray::PArray() +: ElementType(nullptr), ElementCount(0) +{ + mDescriptiveName = "Array"; +} + +//========================================================================== +// +// PArray - Parameterized Constructor +// +//========================================================================== + +PArray::PArray(PType *etype, unsigned int ecount) +: ElementType(etype), ElementCount(ecount) +{ + mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); + + Align = etype->Align; + // Since we are concatenating elements together, the element size should + // also be padded to the nearest alignment. + ElementSize = (etype->Size + (etype->Align - 1)) & ~(etype->Align - 1); + Size = ElementSize * ecount; +} + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == ElementCount; +} + +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = ElementCount; +} + +//========================================================================== +// +// PArray :: WriteValue +// +//========================================================================== + +void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (ar.BeginArray(key)) + { + const uint8_t *addrb = (const uint8_t *)addr; + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->WriteValue(ar, nullptr, addrb); + addrb += ElementSize; + } + ar.EndArray(); + } +} + +//========================================================================== +// +// PArray :: ReadValue +// +//========================================================================== + +bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (ar.BeginArray(key)) + { + bool readsomething = false; + unsigned count = ar.ArraySize(); + unsigned loop = MIN(count, ElementCount); + uint8_t *addrb = (uint8_t *)addr; + for(unsigned i=0;iReadValue(ar, nullptr, addrb); + addrb += ElementSize; + } + if (loop < count) + { + DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", + count, ElementCount); + } + ar.EndArray(); + return readsomething; + } + return false; +} + +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetDefaultValue(base, offset + i*ElementSize, special); + } +} + +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetPointer(void *base, unsigned offset, TArray *special) +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetPointer(base, offset + i*ElementSize, special); + } +} + +//========================================================================== +// +// NewArray +// +// Returns a PArray for the given type and size, making sure not to create +// duplicates. +// +//========================================================================== + +PArray *NewArray(PType *type, unsigned int count) +{ + size_t bucket; + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PArray), (intptr_t)type, count, &bucket); + if (atype == nullptr) + { + atype = new PArray(type, count); + TypeTable.AddType(atype, RUNTIME_CLASS(PArray), (intptr_t)type, count, bucket); + } + return (PArray *)atype; +} + +/* PArray *****************************************************************/ + +IMPLEMENT_CLASS(PStaticArray, false, false) + +//========================================================================== +// +// PArray - Default Constructor +// +//========================================================================== + +PStaticArray::PStaticArray() +{ + mDescriptiveName = "ResizableArray"; +} + +//========================================================================== +// +// PArray - Parameterized Constructor +// +//========================================================================== + +PStaticArray::PStaticArray(PType *etype) + : PArray(etype, 0) +{ + mDescriptiveName.Format("ResizableArray<%s>", etype->DescriptiveName()); +} + +//========================================================================== +// +// PArray :: IsMatch +// +//========================================================================== + +bool PStaticArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *elemtype = (const PType *)id1; + unsigned int count = (unsigned int)(intptr_t)id2; + + return elemtype == ElementType && count == 0; +} + +//========================================================================== +// +// PArray :: GetTypeIDs +// +//========================================================================== + +void PStaticArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + id2 = 0; +} + +//========================================================================== +// +// NewStaticArray +// +// Returns a PArray for the given type and size, making sure not to create +// duplicates. +// +//========================================================================== + +PStaticArray *NewStaticArray(PType *type) +{ + size_t bucket; + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, &bucket); + if (atype == nullptr) + { + atype = new PStaticArray(type); + TypeTable.AddType(atype, RUNTIME_CLASS(PStaticArray), (intptr_t)type, 0, bucket); + } + return (PStaticArray *)atype; +} + +/* PDynArray **************************************************************/ + +IMPLEMENT_CLASS(PDynArray, false, false) + +//========================================================================== +// +// PDynArray - Default Constructor +// +//========================================================================== + +PDynArray::PDynArray() +: ElementType(nullptr) +{ + mDescriptiveName = "DynArray"; + Size = sizeof(FArray); + Align = alignof(FArray); +} + +//========================================================================== +// +// PDynArray - Parameterized Constructor +// +//========================================================================== + +PDynArray::PDynArray(PType *etype,PStruct *backing) +: ElementType(etype), BackingType(backing) +{ + mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); + Size = sizeof(FArray); + Align = alignof(FArray); +} + +//========================================================================== +// +// PDynArray :: IsMatch +// +//========================================================================== + +bool PDynArray::IsMatch(intptr_t id1, intptr_t id2) const +{ + assert(id2 == 0); + const PType *elemtype = (const PType *)id1; + + return elemtype == ElementType; +} + +//========================================================================== +// +// PDynArray :: GetTypeIDs +// +//========================================================================== + +void PDynArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)ElementType; + 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) +{ + if (base != nullptr) 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(PObjectPointer))) + { + // 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 uint8_t *addrb = (const uint8_t *)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; + + uint8_t *addrb = (uint8_t *)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 +// +// Creates a new DynArray of the given type, making sure not to create a +// duplicate. +// +//========================================================================== + +PDynArray *NewDynArray(PType *type) +{ + size_t bucket; + PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket); + if (atype == nullptr) + { + FString backingname; + + switch (type->GetRegType()) + { + case REGT_INT: + backingname.Format("DynArray_I%d", type->Size * 8); + break; + + case REGT_FLOAT: + backingname.Format("DynArray_F%d", type->Size * 8); + break; + + case REGT_STRING: + backingname = "DynArray_String"; + break; + + case REGT_POINTER: + backingname = "DynArray_Ptr"; + break; + + default: + I_Error("Unsupported dynamic array requested"); + break; + } + + auto backing = NewStruct(backingname, nullptr, true); + atype = new PDynArray(type, backing); + TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket); + } + return (PDynArray *)atype; +} + +/* PMap *******************************************************************/ + +IMPLEMENT_CLASS(PMap, false, false) + +//========================================================================== +// +// PMap - Default Constructor +// +//========================================================================== + +PMap::PMap() +: KeyType(nullptr), ValueType(nullptr) +{ + mDescriptiveName = "Map"; + Size = sizeof(FMap); + Align = alignof(FMap); +} + +//========================================================================== +// +// PMap - Parameterized Constructor +// +//========================================================================== + +PMap::PMap(PType *keytype, PType *valtype) +: KeyType(keytype), ValueType(valtype) +{ + mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); + Size = sizeof(FMap); + Align = alignof(FMap); +} + +//========================================================================== +// +// PMap :: IsMatch +// +//========================================================================== + +bool PMap::IsMatch(intptr_t id1, intptr_t id2) const +{ + const PType *keyty = (const PType *)id1; + const PType *valty = (const PType *)id2; + + return keyty == KeyType && valty == ValueType; +} + +//========================================================================== +// +// PMap :: GetTypeIDs +// +//========================================================================== + +void PMap::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)KeyType; + id2 = (intptr_t)ValueType; +} + +//========================================================================== +// +// NewMap +// +// Returns a PMap for the given key and value types, ensuring not to create +// duplicates. +// +//========================================================================== + +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 == nullptr) + { + maptype = new PMap(keytype, valuetype); + TypeTable.AddType(maptype, RUNTIME_CLASS(PMap), (intptr_t)keytype, (intptr_t)valuetype, bucket); + } + return (PMap *)maptype; +} + +/* PStruct ****************************************************************/ + +IMPLEMENT_CLASS(PStruct, false, false) + +//========================================================================== +// +// PStruct - Default Constructor +// +//========================================================================== + +PStruct::PStruct() +{ + mDescriptiveName = "Struct"; + Size = 0; +} + +//========================================================================== +// +// PStruct - Parameterized Constructor +// +//========================================================================== + +PStruct::PStruct(FName name, PTypeBase *outer, bool isnative) +: PContainerType(name, outer) +{ + mDescriptiveName.Format("%sStruct<%s>", isnative? "Native" : "", name.GetChars()); + Size = 0; + isNative = isnative; +} + +//========================================================================== +// +// PStruct :: SetDefaultValue +// +//========================================================================== + +void PStruct::SetDefaultValue(void *base, unsigned offset, TArray *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: SetPointer +// +//========================================================================== + +void PStruct::SetPointer(void *base, unsigned offset, TArray *special) +{ + auto it = Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (it.NextPair(pair)) + { + auto field = dyn_cast(pair->Value); + if (field && !(field->Flags & VARF_Transient)) + { + field->Type->SetPointer(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: WriteValue +// +//========================================================================== + +void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) const +{ + if (ar.BeginObject(key)) + { + Symbols.WriteFields(ar, addr); + ar.EndObject(); + } +} + +//========================================================================== +// +// PStruct :: ReadValue +// +//========================================================================== + +bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + if (ar.BeginObject(key)) + { + bool ret = Symbols.ReadFields(ar, addr, DescriptiveName()); + ar.EndObject(); + return ret; + } + return false; +} + +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new field to the end of a struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddField(FName name, PType *type, uint32_t flags) +{ + return Symbols.AddField(name, type, flags, Size, &Align); +} + +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new native field to the struct. Returns either the new field +// or nullptr if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + return Symbols.AddNativeField(name, type, address, flags, bitvalue); +} + +//========================================================================== +// +// NewStruct +// Returns a PStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PStruct *NewStruct(FName name, PTypeBase *outer, bool native) +{ + 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 == nullptr) + { + stype = new PStruct(name, outer, native); + TypeTable.AddType(stype, RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(stype); +} + + +/* PPrototype *************************************************************/ + +IMPLEMENT_CLASS(PPrototype, false, false) + +//========================================================================== +// +// PPrototype - Default Constructor +// +//========================================================================== + +PPrototype::PPrototype() +{ +} + +//========================================================================== +// +// PPrototype - Parameterized Constructor +// +//========================================================================== + +PPrototype::PPrototype(const TArray &rettypes, const TArray &argtypes) +: ArgumentTypes(argtypes), ReturnTypes(rettypes) +{ +} + +//========================================================================== +// +// PPrototype :: IsMatch +// +//========================================================================== + +bool PPrototype::IsMatch(intptr_t id1, intptr_t id2) const +{ + const TArray *args = (const TArray *)id1; + const TArray *rets = (const TArray *)id2; + + return *args == ArgumentTypes && *rets == ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: GetTypeIDs +// +//========================================================================== + +void PPrototype::GetTypeIDs(intptr_t &id1, intptr_t &id2) const +{ + id1 = (intptr_t)&ArgumentTypes; + id2 = (intptr_t)&ReturnTypes; +} + +//========================================================================== +// +// PPrototype :: PropagateMark +// +//========================================================================== + +size_t PPrototype::PropagateMark() +{ + GC::MarkArray(ArgumentTypes); + GC::MarkArray(ReturnTypes); + return (ArgumentTypes.Size() + ReturnTypes.Size()) * sizeof(void*) + + Super::PropagateMark(); +} + +//========================================================================== +// +// NewPrototype +// +// Returns a PPrototype for the given return and argument types, making sure +// not to create duplicates. +// +//========================================================================== + +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes) +{ + size_t bucket; + PType *proto = TypeTable.FindType(RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, &bucket); + if (proto == nullptr) + { + proto = new PPrototype(rettypes, argtypes); + TypeTable.AddType(proto, RUNTIME_CLASS(PPrototype), (intptr_t)&argtypes, (intptr_t)&rettypes, bucket); + } + return static_cast(proto); +} + +/* PClass *****************************************************************/ + +IMPLEMENT_CLASS(PClassType, false, false) + +//========================================================================== +// +// +// +//========================================================================== + +PClassType::PClassType(PClass *cls) +{ + assert(cls->VMType == nullptr); + Descriptor = cls; + TypeName = cls->TypeName; + if (cls->ParentClass != nullptr) + { + ParentType = cls->ParentClass->VMType; + assert(ParentType != nullptr); + Symbols.SetParentTable(&ParentType->Symbols); + } + cls->VMType = this; + mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); +} + +//========================================================================== +// +// PClass :: AddField +// +//========================================================================== + +PField *PClassType::AddField(FName name, PType *type, uint32_t flags) +{ + return Descriptor->AddField(name, type, flags); +} + +//========================================================================== +// +// PClass :: AddNativeField +// +//========================================================================== + +PField *PClassType::AddNativeField(FName name, PType *type, size_t address, uint32_t flags, int bitvalue) +{ + auto field = Symbols.AddNativeField(name, type, address, flags, bitvalue); + if (field != nullptr) Descriptor->Fields.Push(field); + return field; +} + +//========================================================================== +// +// +// +//========================================================================== + +PClassType *NewClassType(PClass *cls) +{ + size_t bucket; + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, &bucket); + if (ptype == nullptr) + { + ptype = new PClassType(cls); + TypeTable.AddType(ptype, RUNTIME_CLASS(PClassType), 0, (intptr_t)cls->TypeName, bucket); + } + return static_cast(ptype); +} + + +/* FTypeTable **************************************************************/ + +//========================================================================== +// +// FTypeTable :: FindType +// +//========================================================================== + +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 != nullptr) + { + *bucketnum = bucket; + } + for (PType *type = TypeHash[bucket]; type != nullptr; type = type->HashNext) + { + if (type->TypeTableType == metatype && type->IsMatch(parm1, parm2)) + { + return type; + } + } + return nullptr; +} + +//========================================================================== +// +// FTypeTable :: AddType - Fully Parameterized Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket) +{ +#ifdef _DEBUG + size_t bucketcheck; + 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; + type->Release(); +} + +//========================================================================== +// +// FTypeTable :: AddType - Simple Version +// +//========================================================================== + +void FTypeTable::AddType(PType *type) +{ + intptr_t parm1, parm2; + size_t bucket; + + // 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"); + + type->HashNext = TypeHash[bucket]; + TypeHash[bucket] = type; + type->Release(); +} + +//========================================================================== +// +// FTypeTable :: Hash STATIC +// +//========================================================================== + +size_t FTypeTable::Hash(const PClass *p1, intptr_t p2, intptr_t p3) +{ + size_t i1 = (size_t)p1; + + // Swap the high and low halves of i1. The compiler should be smart enough + // to transform this into a ROR or ROL. + i1 = (i1 >> (sizeof(size_t)*4)) | (i1 << (sizeof(size_t)*4)); + + if (p1 != RUNTIME_CLASS(PPrototype)) + { + size_t i2 = (size_t)p2; + size_t i3 = (size_t)p3; + return (~i1 ^ i2) + i3 * 961748927; // i3 is multiplied by a prime + } + else + { // Prototypes need to hash the TArrays at p2 and p3 + const TArray *a2 = (const TArray *)p2; + const TArray *a3 = (const TArray *)p3; + for (unsigned i = 0; i < a2->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a2)[i]); + } + for (unsigned i = 0; i < a3->Size(); ++i) + { + i1 = (i1 * 961748927) + (size_t)((*a3)[i]); + } + return i1; + } +} + +//========================================================================== +// +// FTypeTable :: Clear +// +//========================================================================== + +void FTypeTable::Clear() +{ + for (size_t i = 0; i < countof(TypeTable.TypeHash); ++i) + { + for (PType *ty = TypeTable.TypeHash[i]; ty != nullptr;) + { + auto next = ty->HashNext; + delete ty; + ty = next; + } + } + memset(TypeHash, 0, sizeof(TypeHash)); +} + +#include "c_dispatch.h" +CCMD(typetable) +{ + DumpTypeTable(); +} + diff --git a/src/scripting/types.h b/src/scripting/types.h new file mode 100644 index 000000000..3c233c617 --- /dev/null +++ b/src/scripting/types.h @@ -0,0 +1,641 @@ +#pragma once + +#include "dobject.h" +#include "serializer.h" + +// Variable/parameter/field flags ------------------------------------------- +class PStruct; + +// Making all these different storage types use a common set of flags seems +// like the simplest thing to do. + +enum +{ + VARF_Optional = (1<<0), // func param is optional + VARF_Method = (1<<1), // func has an implied self parameter + VARF_Action = (1<<2), // func has implied owner and state parameters + VARF_Native = (1<<3), // func is native code, field is natively defined + VARF_ReadOnly = (1<<4), // field is read only, do not write to it + VARF_Private = (1<<5), // field is private to containing class + VARF_Protected = (1<<6), // field is only accessible by containing class and children. + VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used. + VARF_Virtual = (1<<8), // function is virtual + VARF_Final = (1<<9), // Function may not be overridden in subclasses + VARF_In = (1<<10), + VARF_Out = (1<<11), + VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) + VARF_Static = (1<<13), + VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. + VARF_Override = (1<<15), // overrides a virtual function from the parent class. + VARF_Ref = (1<<16), // argument is passed by reference. + VARF_Transient = (1<<17), // don't auto serialize field. + VARF_Meta = (1<<18), // static class data (by necessity read only.) + VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature + VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim) + VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui) + VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only) + VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data. +}; + +// Basic information shared by all types ------------------------------------ + +// Only one copy of a type is ever instantiated at one time. +// - Enums, classes, and structs are defined by their names and outer classes. +// - Pointers are uniquely defined by the type they point at. +// - ClassPointers are also defined by their class restriction. +// - Arrays are defined by their element type and count. +// - DynArrays are defined by their element type. +// - Maps are defined by their key and value types. +// - Prototypes are defined by the argument and return types. +// - Functions are defined by their names and outer objects. +// In table form: +// Outer Name Type Type2 Count +// Enum * * +// Class * * +// Struct * * +// Function * * +// Pointer * +// ClassPointer + * +// Array * * +// DynArray * +// Map * * +// Prototype *+ *+ + +struct ZCC_ExprConstant; +class PType : public PTypeBase +{ + DECLARE_ABSTRACT_CLASS(PType, PTypeBase) +protected: + +public: + 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 + PSymbolTable Symbols; + bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument. + FString mDescriptiveName; + VersionInfo mVersion = { 0,0,0 }; + uint8_t loadOp, storeOp, moveOp, RegType, RegCount; + + PType(unsigned int size = 1, unsigned int align = 1); + virtual ~PType(); + virtual bool isNumeric() { return false; } + + // Writes the value of a variable of this type at (addr) to an archive, preceded by + // a tag indicating its type. The tag is there so that variable types can be changed + // without completely breaking savegames, provided that the change isn't between + // totally unrelated types. + virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const; + + // Returns true if the stored value was compatible. False otherwise. + // If the value was incompatible, then the memory at *addr is unchanged. + virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const; + + // 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); + virtual void SetPointer(void *base, unsigned offset, TArray *ptrofs = NULL); + 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; + + // 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); + + // Gets the value of a variable of this type at (addr) + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; + + // Gets the opcode to store from a register to memory + int GetStoreOp() const + { + return storeOp; + } + + // Gets the opcode to load from memory to a register + int GetLoadOp() const + { + return loadOp; + } + + // Gets the opcode to move from register to another register + int GetMoveOp() const + { + return moveOp; + } + + // Gets the register type for this type + int GetRegType() const + { + return RegType; + } + + int GetRegCount() const + { + return RegCount; + } + // Returns true if this type matches the two identifiers. Referring to the + // above table, any type is identified by at most two characteristics. Each + // type that implements this function will cast these to the appropriate type. + // It is up to the caller to make sure they are the correct types. There is + // only one prototype for this function in order to simplify type table + // management. + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + + // Get the type IDs used by IsMatch + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + + const char *DescriptiveName() const; + + static void StaticInit(); +}; + +// Not-really-a-type types -------------------------------------------------- + +class PErrorType : public PType +{ + DECLARE_CLASS(PErrorType, PType); +public: + PErrorType(int which = 1) : PType(0, which) {} +}; + +class PVoidType : public PType +{ + DECLARE_CLASS(PVoidType, PType); +public: + PVoidType() : PType(0, 1) {} +}; + +// Some categorization typing ----------------------------------------------- + +class PBasicType : public PType +{ + DECLARE_ABSTRACT_CLASS(PBasicType, PType); +public: + PBasicType(); + PBasicType(unsigned int size, unsigned int align); +}; + +class PCompoundType : public PType +{ + DECLARE_ABSTRACT_CLASS(PCompoundType, PType); +}; + +class PContainerType : public PCompoundType +{ + DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType); +public: + PTypeBase *Outer; // object this type is contained within + FName TypeName; // this type's name + + PContainerType() : Outer(NULL) { + mDescriptiveName = "NamedType"; + } + PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) { + mDescriptiveName = name.GetChars(); + } + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0; + virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0; +}; + +// Basic types -------------------------------------------------------------- + +class PInt : public PBasicType +{ + DECLARE_CLASS(PInt, PBasicType); +public: + PInt(unsigned int size, bool unsign, bool compatible = true); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + + virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; + virtual bool isNumeric() override { return IntCompatible; } + + bool Unsigned; + bool IntCompatible; +protected: + PInt(); + void SetOps(); +}; + +class PBool : public PInt +{ + DECLARE_CLASS(PBool, PInt); +public: + PBool(); + virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; +}; + +class PFloat : public PBasicType +{ + DECLARE_CLASS(PFloat, PBasicType); +public: + PFloat(unsigned int size); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; + + virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); + virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; + virtual bool isNumeric() override { return true; } +protected: + PFloat(); + void SetOps(); +private: + struct SymbolInitF + { + ENamedName Name; + double Value; + }; + struct SymbolInitI + { + ENamedName Name; + int Value; + }; + + void SetSingleSymbols(); + void SetDoubleSymbols(); + void SetSymbols(const SymbolInitF *syminit, size_t count); + void SetSymbols(const SymbolInitI *syminit, size_t count); +}; + +class PString : public PBasicType +{ + DECLARE_CLASS(PString, PBasicType); +public: + PString(); + + 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 *special=NULL) override; + void InitializeValue(void *addr, const void *def) const override; + void DestroyValue(void *addr) const override; +}; + +// Variations of integer types ---------------------------------------------- + +class PName : public PInt +{ + DECLARE_CLASS(PName, PInt); +public: + PName(); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; +}; + +class PSound : public PInt +{ + DECLARE_CLASS(PSound, PInt); +public: + PSound(); + + void WriteValue(FSerializer &ar, const char *key,const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key,void *addr) const override; +}; + +class PSpriteID : public PInt +{ + DECLARE_CLASS(PSpriteID, PInt); +public: + PSpriteID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + +class PTextureID : public PInt +{ + DECLARE_CLASS(PTextureID, PInt); +public: + PTextureID(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + +class PColor : public PInt +{ + DECLARE_CLASS(PColor, PInt); +public: + PColor(); +}; + +class PStateLabel : public PInt +{ + DECLARE_CLASS(PStateLabel, PInt); +public: + PStateLabel(); +}; + +// Pointers ----------------------------------------------------------------- + +class PPointer : public PBasicType +{ + DECLARE_CLASS(PPointer, PBasicType); + +public: + typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr); + typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr); + + PPointer(); + PPointer(PType *pointsat, bool isconst = false); + + PType *PointedType; + bool IsConst; + + WriteHandler writer = nullptr; + ReadHandler reader = nullptr; + + void InstallHandlers(WriteHandler w, ReadHandler r) + { + writer = w; + reader = r; + } + + 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; + +protected: + void SetOps(); +}; + +class PStatePointer : public PPointer +{ + DECLARE_CLASS(PStatePointer, PPointer); +public: + PStatePointer(); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; +}; + + +class PObjectPointer : public PPointer +{ + DECLARE_CLASS(PObjectPointer, PPointer); +public: + PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false); + + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; + PClass *PointedClass() const; +}; + + +class PClassPointer : public PPointer +{ + DECLARE_CLASS(PClassPointer, PPointer); +public: + PClassPointer(class PClass *restrict = nullptr); + + class PClass *ClassRestriction; + + bool isCompatible(PType *type); + void WriteValue(FSerializer &ar, const char *key, const void *addr) const override; + bool ReadValue(FSerializer &ar, const char *key, void *addr) const override; + + void SetPointer(void *base, unsigned offset, TArray *special = NULL) override; + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +}; + +// Compound types ----------------------------------------------------------- + +class PEnum : public PInt +{ + DECLARE_CLASS(PEnum, PInt); +public: + PEnum(FName name, PTypeBase *outer); + + PTypeBase *Outer; + FName EnumName; +protected: + PEnum(); +}; + +class PArray : public PCompoundType +{ + DECLARE_CLASS(PArray, PCompoundType); +public: + PArray(PType *etype, unsigned int ecount); + + PType *ElementType; + unsigned int ElementCount; + unsigned int ElementSize; + + 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 *special) override; + void SetPointer(void *base, unsigned offset, TArray *special) override; + +protected: + PArray(); +}; + +class PStaticArray : public PArray +{ + DECLARE_CLASS(PStaticArray, PArray); +public: + PStaticArray(PType *etype); + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + +protected: + PStaticArray(); +}; + +class PDynArray : public PCompoundType +{ + DECLARE_CLASS(PDynArray, PCompoundType); +public: + PDynArray(PType *etype, PStruct *backing); + + PType *ElementType; + PStruct *BackingType; + + 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) 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(); +}; + +class PMap : public PCompoundType +{ + DECLARE_CLASS(PMap, PCompoundType); +public: + PMap(PType *keytype, PType *valtype); + + PType *KeyType; + PType *ValueType; + + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PMap(); +}; + +class PStruct : public PContainerType +{ + DECLARE_CLASS(PStruct, PContainerType); + +public: + PStruct(FName name, PTypeBase *outer, bool isnative = false); + + bool isNative; + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it. + VMFunction *mConstructor = nullptr; + VMFunction *mDestructor = nullptr; + + virtual PField *AddField(FName name, PType *type, uint32_t flags=0); + virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0); + + 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) override; + void SetPointer(void *base, unsigned offset, TArray *specials) override; + +protected: + PStruct(); +}; + +class PPrototype : public PCompoundType +{ + DECLARE_CLASS(PPrototype, PCompoundType); +public: + PPrototype(const TArray &rettypes, const TArray &argtypes); + + TArray ArgumentTypes; + TArray ReturnTypes; + + size_t PropagateMark(); + virtual bool IsMatch(intptr_t id1, intptr_t id2) const; + virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; +protected: + PPrototype(); +}; + + +// Meta-info for every class derived from DObject --------------------------- + +class PClassType : public PContainerType +{ + DECLARE_CLASS(PClassType, PContainerType); + +private: + +public: + PClass *Descriptor; + PClassType *ParentType; + + PClassType(PClass *cls = nullptr); + PField *AddField(FName name, PType *type, uint32_t flags = 0) override; + PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override; +}; + + + +// Returns a type from the TypeTable. Will create one if it isn't present. +PMap *NewMap(PType *keytype, PType *valuetype); +PArray *NewArray(PType *type, unsigned int count); +PStaticArray *NewStaticArray(PType *type); +PDynArray *NewDynArray(PType *type); +PPointer *NewPointer(PType *type, bool isconst = false); +PPointer *NewPointer(PClass *type, bool isconst = false); +PClassPointer *NewClassPointer(PClass *restrict); +PEnum *NewEnum(FName name, PTypeBase *outer); +PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false); +PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); +PClassType *NewClassType(PClass *cls); + +// Built-in types ----------------------------------------------------------- + +extern PErrorType *TypeError; +extern PErrorType *TypeAuto; +extern PVoidType *TypeVoid; +extern PInt *TypeSInt8, *TypeUInt8; +extern PInt *TypeSInt16, *TypeUInt16; +extern PInt *TypeSInt32, *TypeUInt32; +extern PBool *TypeBool; +extern PFloat *TypeFloat32, *TypeFloat64; +extern PString *TypeString; +extern PName *TypeName; +extern PSound *TypeSound; +extern PColor *TypeColor; +extern PTextureID *TypeTextureID; +extern PSpriteID *TypeSpriteID; +extern PStruct *TypeVector2; +extern PStruct *TypeVector3; +extern PStruct *TypeColorStruct; +extern PStruct *TypeStringStruct; +extern PStatePointer *TypeState; +extern PPointer *TypeFont; +extern PStateLabel *TypeStateLabel; +extern PPointer *TypeNullPtr; +extern PPointer *TypeVoidPtr; + +inline FString &DObject::StringVar(FName field) +{ + return *(FString*)ScriptVar(field, TypeString); +} + +// Type tables -------------------------------------------------------------- + +struct FTypeTable +{ + enum { HASH_SIZE = 1021 }; + + PType *TypeHash[HASH_SIZE]; + + PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum); + void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket); + void AddType(PType *type); + void Clear(); + + static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3); +}; + + +extern FTypeTable TypeTable; + diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index d05e33a5f..b7b7aa1c5 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -26,134 +26,6 @@ typedef signed int VM_SWORD; #define VM_EPSILON (1/65536.0) -#ifdef __BIG_ENDIAN__ -#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG2, ARG1 -#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG4, ARG3, ARG2, ARG1 -#else // little endian -#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG1, ARG2 -#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG1, ARG2, ARG3, ARG4 -#endif // __BIG_ENDIAN__ - -union VMOP -{ - struct - { - VM_DEFINE_OP4(VM_UBYTE, op, a, b, c); - }; - struct - { - VM_DEFINE_OP4(VM_SBYTE, pad0, as, bs, cs); - }; - struct - { - VM_DEFINE_OP2(VM_SWORD, pad1:8, i24:24); - }; - struct - { - VM_DEFINE_OP2(VM_SWORD, pad2:16, i16:16); - }; - struct - { - VM_DEFINE_OP2(VM_UHALF, pad3, i16u); - }; - VM_UWORD word; - - // Interesting fact: VC++ produces better code for i16 when it's defined - // as a bitfield than when it's defined as two discrete units. - // Compare: - // mov eax,dword ptr [op] ; As two discrete units - // shr eax,10h - // movsx eax,ax - // versus: - // mov eax,dword ptr [op] ; As a bitfield - // sar eax,10h -}; - -#undef VM_DEFINE_OP4 -#undef VM_DEFINE_OP2 - -enum -{ -#include "vmops.h" -NUM_OPS -}; - -// Flags for A field of CMPS -enum -{ - CMP_CHECK = 1, - - CMP_EQ = 0, - CMP_LT = 2, - CMP_LE = 4, - CMP_METHOD_MASK = 6, - - CMP_BK = 8, - CMP_CK = 16, - CMP_APPROX = 32, -}; - -// Floating point operations for FLOP -enum -{ - FLOP_ABS, - FLOP_NEG, - FLOP_EXP, - FLOP_LOG, - FLOP_LOG10, - FLOP_SQRT, - FLOP_CEIL, - FLOP_FLOOR, - - FLOP_ACOS, // This group works with radians - FLOP_ASIN, - FLOP_ATAN, - FLOP_COS, - FLOP_SIN, - FLOP_TAN, - - FLOP_ACOS_DEG, // This group works with degrees - FLOP_ASIN_DEG, - FLOP_ATAN_DEG, - FLOP_COS_DEG, - FLOP_SIN_DEG, - FLOP_TAN_DEG, - - FLOP_COSH, - FLOP_SINH, - FLOP_TANH, -}; - -// Cast operations -enum -{ - CAST_I2F, - CAST_I2S, - CAST_U2F, - CAST_U2S, - CAST_F2I, - CAST_F2U, - CAST_F2S, - CAST_P2S, - CAST_S2I, - CAST_S2F, - CAST_S2N, - CAST_N2S, - CAST_S2Co, - CAST_S2So, - CAST_Co2S, - CAST_So2S, - CAST_V22S, - CAST_V32S, - CAST_SID2S, - CAST_TID2S, - - CASTB_I, - CASTB_F, - CASTB_A, - CASTB_S -}; - // Register types for VMParam enum { @@ -198,105 +70,6 @@ public: // This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown. void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...); -enum EVMOpMode -{ - MODE_ASHIFT = 0, - MODE_BSHIFT = 4, - MODE_CSHIFT = 8, - MODE_BCSHIFT = 12, - - MODE_ATYPE = 15 << MODE_ASHIFT, - MODE_BTYPE = 15 << MODE_BSHIFT, - MODE_CTYPE = 15 << MODE_CSHIFT, - MODE_BCTYPE = 31 << MODE_BCSHIFT, - - MODE_I = 0, - MODE_F, - MODE_S, - MODE_P, - MODE_V, - MODE_X, - MODE_KI, - MODE_KF, - MODE_KS, - MODE_KP, - MODE_KV, - MODE_UNUSED, - MODE_IMMS, - MODE_IMMZ, - MODE_JOINT, - MODE_CMP, - - MODE_PARAM, - MODE_THROW, - MODE_CATCH, - MODE_CAST, - - MODE_AI = MODE_I << MODE_ASHIFT, - MODE_AF = MODE_F << MODE_ASHIFT, - MODE_AS = MODE_S << MODE_ASHIFT, - MODE_AP = MODE_P << MODE_ASHIFT, - MODE_AV = MODE_V << MODE_ASHIFT, - MODE_AX = MODE_X << MODE_ASHIFT, - MODE_AKP = MODE_KP << MODE_ASHIFT, - MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT, - MODE_AIMMS = MODE_IMMS << MODE_ASHIFT, - MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT, - MODE_ACMP = MODE_CMP << MODE_ASHIFT, - - MODE_BI = MODE_I << MODE_BSHIFT, - MODE_BF = MODE_F << MODE_BSHIFT, - MODE_BS = MODE_S << MODE_BSHIFT, - MODE_BP = MODE_P << MODE_BSHIFT, - MODE_BV = MODE_V << MODE_BSHIFT, - MODE_BX = MODE_X << MODE_BSHIFT, - MODE_BKI = MODE_KI << MODE_BSHIFT, - MODE_BKF = MODE_KF << MODE_BSHIFT, - MODE_BKS = MODE_KS << MODE_BSHIFT, - MODE_BKP = MODE_KP << MODE_BSHIFT, - MODE_BKV = MODE_KV << MODE_BSHIFT, - MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT, - MODE_BIMMS = MODE_IMMS << MODE_BSHIFT, - MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT, - - MODE_CI = MODE_I << MODE_CSHIFT, - MODE_CF = MODE_F << MODE_CSHIFT, - MODE_CS = MODE_S << MODE_CSHIFT, - MODE_CP = MODE_P << MODE_CSHIFT, - MODE_CV = MODE_V << MODE_CSHIFT, - MODE_CX = MODE_X << MODE_CSHIFT, - MODE_CKI = MODE_KI << MODE_CSHIFT, - MODE_CKF = MODE_KF << MODE_CSHIFT, - MODE_CKS = MODE_KS << MODE_CSHIFT, - MODE_CKP = MODE_KP << MODE_CSHIFT, - MODE_CKV = MODE_KV << MODE_CSHIFT, - MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT, - MODE_CIMMS = MODE_IMMS << MODE_CSHIFT, - MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT, - - MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT), - MODE_BCKI = MODE_KI << MODE_BCSHIFT, - MODE_BCKF = MODE_KF << MODE_BCSHIFT, - MODE_BCKS = MODE_KS << MODE_BCSHIFT, - MODE_BCKP = MODE_KP << MODE_BCSHIFT, - MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT, - MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT, - MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT, - MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT, - MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT, - MODE_BCCAST = MODE_CAST << MODE_BCSHIFT, - - MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT, -}; - -struct VMOpInfo -{ - const char *Name; - int Mode; -}; - -extern const VMOpInfo OpInfo[NUM_OPS]; - struct VMReturn { void *Location; @@ -544,186 +317,6 @@ public: protected: }; -// VM frame layout: -// VMFrame header -// parameter stack - 16 byte boundary, 16 bytes each -// double registers - 8 bytes each -// string registers - 4 or 8 bytes each -// address registers - 4 or 8 bytes each -// data registers - 4 bytes each -// address register tags-1 byte each -// extra space - 16 byte boundary -struct VMFrame -{ - VMFrame *ParentFrame; - VMFunction *Func; - VM_UBYTE NumRegD; - VM_UBYTE NumRegF; - VM_UBYTE NumRegS; - VM_UBYTE NumRegA; - VM_UHALF MaxParam; - VM_UHALF NumParam; // current number of parameters - - static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra) - { - int size = (sizeof(VMFrame) + 15) & ~15; - size += numparam * sizeof(VMValue); - size += numregf * sizeof(double); - size += numrega * sizeof(void *); - size += numregs * sizeof(FString); - size += numregd * sizeof(int); - if (numextra != 0) - { - size = (size + 15) & ~15; - size += numextra; - } - return size; - } - - VMValue *GetParam() const - { - assert(((size_t)this & 15) == 0 && "VM frame is unaligned"); - return (VMValue *)(((size_t)(this + 1) + 15) & ~15); - } - - double *GetRegF() const - { - return (double *)(GetParam() + MaxParam); - } - - FString *GetRegS() const - { - return (FString *)(GetRegF() + NumRegF); - } - - void **GetRegA() const - { - return (void **)(GetRegS() + NumRegS); - } - - int *GetRegD() const - { - return (int *)(GetRegA() + NumRegA); - } - - void *GetExtra() const - { - uint8_t *pbeg = (uint8_t*)(GetRegD() + NumRegD); - ptrdiff_t ofs = pbeg - (uint8_t *)this; - return (VM_UBYTE *)this + ((ofs + 15) & ~15); - } - - void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VMValue *¶m) const - { - // Calling the individual functions produces suboptimal code. :( - param = GetParam(); - f = (double *)(param + MaxParam); - s = (FString *)(f + NumRegF); - a = (void **)(s + NumRegS); - d = (int *)(a + NumRegA); - } - - void InitRegS(); -}; - -struct VMRegisters -{ - VMRegisters(const VMFrame *frame) - { - frame->GetAllRegs(d, f, s, a, param); - } - - VMRegisters(const VMRegisters &o) - : d(o.d), f(o.f), s(o.s), a(o.a), param(o.param) - { } - - int *d; - double *f; - FString *s; - void **a; - VMValue *param; -}; - -union FVoidObj -{ - DObject *o; - void *v; -}; - -struct FStatementInfo -{ - uint16_t InstructionIndex; - uint16_t LineNumber; -}; - -class VMScriptFunction : public VMFunction -{ -public: - VMScriptFunction(FName name=NAME_None); - ~VMScriptFunction(); - void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); - - VMOP *Code; - FStatementInfo *LineInfo; - FString SourceFileName; - int *KonstD; - double *KonstF; - FString *KonstS; - FVoidObj *KonstA; - int ExtraSpace; - int CodeSize; // Size of code in instructions (not bytes) - unsigned LineInfoCount; - unsigned StackSize; - VM_UBYTE NumRegD; - VM_UBYTE NumRegF; - VM_UBYTE NumRegS; - VM_UBYTE NumRegA; - VM_UHALF NumKonstD; - VM_UHALF NumKonstF; - VM_UHALF NumKonstS; - VM_UHALF NumKonstA; - VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once - VM_UBYTE NumArgs; // Number of arguments this function takes - TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction - - void InitExtra(void *addr); - void DestroyExtra(void *addr); - int AllocExtraStack(PType *type); - int PCToLine(const VMOP *pc); -}; - -class VMFrameStack -{ -public: - VMFrameStack(); - ~VMFrameStack(); - VMFrame *AllocFrame(VMScriptFunction *func); - VMFrame *PopFrame(); - VMFrame *TopFrame() - { - assert(Blocks != NULL && Blocks->LastFrame != NULL); - return Blocks->LastFrame; - } - int Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap=NULL); -private: - enum { BLOCK_SIZE = 4096 }; // Default block size - struct BlockHeader - { - BlockHeader *NextBlock; - VMFrame *LastFrame; - VM_UBYTE *FreeSpace; - int BlockSize; - - void InitFreeSpace() - { - FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15); - } - }; - BlockHeader *Blocks; - BlockHeader *UnusedBlocks; - VMFrame *Alloc(int size); -}; - class VMNativeFunction : public VMFunction { public: @@ -738,66 +331,7 @@ public: NativeCallType NativeCall; }; -class VMParamFiller -{ -public: - VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {} - VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {} - - void ParamInt(int val) - { - Reg.d[RegD++] = val; - } - - void ParamFloat(double val) - { - Reg.f[RegF++] = val; - } - - void ParamString(FString &val) - { - Reg.s[RegS++] = val; - } - - void ParamString(const char *val) - { - Reg.s[RegS++] = val; - } - - void ParamObject(DObject *obj) - { - Reg.a[RegA] = obj; - RegA++; - } - - void ParamPointer(void *ptr) - { - Reg.a[RegA] = ptr; - RegA++; - } - -private: - const VMRegisters Reg; - int RegD, RegF, RegS, RegA; -}; - - -enum EVMEngine -{ - VMEngine_Default, - VMEngine_Unchecked, - VMEngine_Checked -}; - -extern thread_local VMFrameStack GlobalVMStack; - - -void VMSelectEngine(EVMEngine engine); -extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); -void VMFillParams(VMValue *params, VMFrame *callee, int numparam); - -void VMDumpConstants(FILE *out, const VMScriptFunction *func); -void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); +int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/); // Use this in the prototype for a native function. #define VM_ARGS VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret @@ -1004,7 +538,7 @@ class AActor; #define ACTION_CALL_FROM_PSPRITE() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite) #define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain) -// Standard parameters for all action functons +// Standard parameters for all action functions // self - Actor this action is to operate on (player if a weapon) // stateowner - Actor this action really belongs to (may be an item) // callingstate - State this action was called from @@ -1033,4 +567,29 @@ VMFunction *FindVMFunction(PClass *cls, const char *name); FString FStringFormat(VM_ARGS); + +unsigned GetVirtualIndex(PClass *cls, const char *funcname); + +#define IFVIRTUALPTR(self, cls, funcname) \ + static unsigned VIndex = ~0u; \ + if (VIndex == ~0u) { \ + VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ + assert(VIndex != ~0u); \ + } \ + auto clss = self->GetClass(); \ + VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ + if (func != nullptr) + +#define IFVIRTUAL(cls, funcname) IFVIRTUALPTR(this, cls, funcname) + +#define IFVIRTUALPTRNAME(self, cls, funcname) \ + static unsigned VIndex = ~0u; \ + if (VIndex == ~0u) { \ + VIndex = GetVirtualIndex(PClass::FindClass(cls), #funcname); \ + assert(VIndex != ~0u); \ + } \ + auto clss = self->GetClass(); \ + VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ + if (func != nullptr) + #endif diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 1e3afd709..0bad8c055 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -40,12 +40,16 @@ #include "textures/textures.h" #include "math/cmath.h" #include "stats.h" +#include "vmintern.h" +#include "types.h" extern cycle_t VMCycles[10]; extern int VMCalls[10]; // intentionally implemented in a different source file to prevent inlining. +#if 0 void ThrowVMException(VMException *x); +#endif #define IMPLEMENT_VMEXEC diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index a62627cc4..b573c0670 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -215,16 +215,6 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) GETADDR(PB,RC,X_READ_NIL); reg.a[a] = GC::ReadBarrier(*(DObject **)ptr); NEXTOP; - OP(LOS): - ASSERTA(a); ASSERTA(B); ASSERTKD(C); - GETADDR(PB,KC,X_READ_NIL); - reg.a[a] = *(DObject **)ptr; - NEXTOP; - OP(LOS_R): - ASSERTA(a); ASSERTA(B); ASSERTD(C); - GETADDR(PB,RC,X_READ_NIL); - reg.a[a] = *(DObject **)ptr; - NEXTOP; OP(LP): ASSERTA(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index c631dea74..69a6febbf 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -36,12 +36,17 @@ #include "dobject.h" #include "v_text.h" #include "stats.h" +#include "c_dispatch.h" #include "templates.h" +#include "vmintern.h" +#include "types.h" cycle_t VMCycles[10]; int VMCalls[10]; +#if 0 IMPLEMENT_CLASS(VMException, false, false) +#endif TArray VMFunction::AllFunctions; @@ -423,9 +428,8 @@ VMFrame *VMFrameStack::PopFrame() // //=========================================================================== -int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) +int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap*/) { - assert(this == &GlobalVMStack); // why would anyone even want to create a local stack? bool allocated = false; try { @@ -452,16 +456,18 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur { VMCycles[0].Clock(); VMCalls[0]++; - AllocFrame(static_cast(func)); + auto &stack = GlobalVMStack; + stack.AllocFrame(static_cast(func)); allocated = true; - VMFillParams(params, TopFrame(), numparams); - int numret = VMExec(this, code, results, numresults); - PopFrame(); + VMFillParams(params, stack.TopFrame(), numparams); + int numret = VMExec(&stack, code, results, numresults); + stack.PopFrame(); VMCycles[0].Unclock(); return numret; } } } +#if 0 catch (VMException *exception) { if (allocated) @@ -475,11 +481,12 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } +#endif catch (...) { if (allocated) { - PopFrame(); + GlobalVMStack.PopFrame(); } throw; } @@ -576,10 +583,12 @@ void NullParam(const char *varname) ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); } +#if 0 void ThrowVMException(VMException *x) { throw x; } +#endif ADD_STAT(VM) @@ -599,3 +608,32 @@ ADD_STAT(VM) VMCalls[0] = 0; return FStringf("VM time in last 10 tics: %f ms, %d calls, peak = %f ms", added, addedc, peak); } + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(vmengine) +{ + if (argv.argc() == 2) + { + if (stricmp(argv[1], "default") == 0) + { + VMSelectEngine(VMEngine_Default); + return; + } + else if (stricmp(argv[1], "checked") == 0) + { + VMSelectEngine(VMEngine_Checked); + return; + } + else if (stricmp(argv[1], "unchecked") == 0) + { + VMSelectEngine(VMEngine_Unchecked); + return; + } + } + Printf("Usage: vmengine \n"); +} + diff --git a/src/scripting/vm/vmintern.h b/src/scripting/vm/vmintern.h new file mode 100644 index 000000000..e79a2360d --- /dev/null +++ b/src/scripting/vm/vmintern.h @@ -0,0 +1,474 @@ +#pragma once + +#include "vm.h" + +class VMScriptFunction; + +#ifdef __BIG_ENDIAN__ +#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG2, ARG1 +#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG4, ARG3, ARG2, ARG1 +#else // little endian +#define VM_DEFINE_OP2(TYPE, ARG1, ARG2) TYPE ARG1, ARG2 +#define VM_DEFINE_OP4(TYPE, ARG1, ARG2, ARG3, ARG4) TYPE ARG1, ARG2, ARG3, ARG4 +#endif // __BIG_ENDIAN__ + +union VMOP +{ + struct + { + VM_DEFINE_OP4(VM_UBYTE, op, a, b, c); + }; + struct + { + VM_DEFINE_OP4(VM_SBYTE, pad0, as, bs, cs); + }; + struct + { + VM_DEFINE_OP2(VM_SWORD, pad1:8, i24:24); + }; + struct + { + VM_DEFINE_OP2(VM_SWORD, pad2:16, i16:16); + }; + struct + { + VM_DEFINE_OP2(VM_UHALF, pad3, i16u); + }; + VM_UWORD word; + + // Interesting fact: VC++ produces better code for i16 when it's defined + // as a bitfield than when it's defined as two discrete units. + // Compare: + // mov eax,dword ptr [op] ; As two discrete units + // shr eax,10h + // movsx eax,ax + // versus: + // mov eax,dword ptr [op] ; As a bitfield + // sar eax,10h +}; + +#undef VM_DEFINE_OP4 +#undef VM_DEFINE_OP2 + +enum +{ +#include "vmops.h" +NUM_OPS +}; + +// Flags for A field of CMPS +enum +{ + CMP_CHECK = 1, + + CMP_EQ = 0, + CMP_LT = 2, + CMP_LE = 4, + CMP_METHOD_MASK = 6, + + CMP_BK = 8, + CMP_CK = 16, + CMP_APPROX = 32, +}; + +// Floating point operations for FLOP +enum +{ + FLOP_ABS, + FLOP_NEG, + FLOP_EXP, + FLOP_LOG, + FLOP_LOG10, + FLOP_SQRT, + FLOP_CEIL, + FLOP_FLOOR, + + FLOP_ACOS, // This group works with radians + FLOP_ASIN, + FLOP_ATAN, + FLOP_COS, + FLOP_SIN, + FLOP_TAN, + + FLOP_ACOS_DEG, // This group works with degrees + FLOP_ASIN_DEG, + FLOP_ATAN_DEG, + FLOP_COS_DEG, + FLOP_SIN_DEG, + FLOP_TAN_DEG, + + FLOP_COSH, + FLOP_SINH, + FLOP_TANH, +}; + +// Cast operations +enum +{ + CAST_I2F, + CAST_I2S, + CAST_U2F, + CAST_U2S, + CAST_F2I, + CAST_F2U, + CAST_F2S, + CAST_P2S, + CAST_S2I, + CAST_S2F, + CAST_S2N, + CAST_N2S, + CAST_S2Co, + CAST_S2So, + CAST_Co2S, + CAST_So2S, + CAST_V22S, + CAST_V32S, + CAST_SID2S, + CAST_TID2S, + + CASTB_I, + CASTB_F, + CASTB_A, + CASTB_S +}; + +enum EVMOpMode +{ + MODE_ASHIFT = 0, + MODE_BSHIFT = 4, + MODE_CSHIFT = 8, + MODE_BCSHIFT = 12, + + MODE_ATYPE = 15 << MODE_ASHIFT, + MODE_BTYPE = 15 << MODE_BSHIFT, + MODE_CTYPE = 15 << MODE_CSHIFT, + MODE_BCTYPE = 31 << MODE_BCSHIFT, + + MODE_I = 0, + MODE_F, + MODE_S, + MODE_P, + MODE_V, + MODE_X, + MODE_KI, + MODE_KF, + MODE_KS, + MODE_KP, + MODE_KV, + MODE_UNUSED, + MODE_IMMS, + MODE_IMMZ, + MODE_JOINT, + MODE_CMP, + + MODE_PARAM, + MODE_THROW, + MODE_CATCH, + MODE_CAST, + + MODE_AI = MODE_I << MODE_ASHIFT, + MODE_AF = MODE_F << MODE_ASHIFT, + MODE_AS = MODE_S << MODE_ASHIFT, + MODE_AP = MODE_P << MODE_ASHIFT, + MODE_AV = MODE_V << MODE_ASHIFT, + MODE_AX = MODE_X << MODE_ASHIFT, + MODE_AKP = MODE_KP << MODE_ASHIFT, + MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT, + MODE_AIMMS = MODE_IMMS << MODE_ASHIFT, + MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT, + MODE_ACMP = MODE_CMP << MODE_ASHIFT, + + MODE_BI = MODE_I << MODE_BSHIFT, + MODE_BF = MODE_F << MODE_BSHIFT, + MODE_BS = MODE_S << MODE_BSHIFT, + MODE_BP = MODE_P << MODE_BSHIFT, + MODE_BV = MODE_V << MODE_BSHIFT, + MODE_BX = MODE_X << MODE_BSHIFT, + MODE_BKI = MODE_KI << MODE_BSHIFT, + MODE_BKF = MODE_KF << MODE_BSHIFT, + MODE_BKS = MODE_KS << MODE_BSHIFT, + MODE_BKP = MODE_KP << MODE_BSHIFT, + MODE_BKV = MODE_KV << MODE_BSHIFT, + MODE_BUNUSED = MODE_UNUSED << MODE_BSHIFT, + MODE_BIMMS = MODE_IMMS << MODE_BSHIFT, + MODE_BIMMZ = MODE_IMMZ << MODE_BSHIFT, + + MODE_CI = MODE_I << MODE_CSHIFT, + MODE_CF = MODE_F << MODE_CSHIFT, + MODE_CS = MODE_S << MODE_CSHIFT, + MODE_CP = MODE_P << MODE_CSHIFT, + MODE_CV = MODE_V << MODE_CSHIFT, + MODE_CX = MODE_X << MODE_CSHIFT, + MODE_CKI = MODE_KI << MODE_CSHIFT, + MODE_CKF = MODE_KF << MODE_CSHIFT, + MODE_CKS = MODE_KS << MODE_CSHIFT, + MODE_CKP = MODE_KP << MODE_CSHIFT, + MODE_CKV = MODE_KV << MODE_CSHIFT, + MODE_CUNUSED = MODE_UNUSED << MODE_CSHIFT, + MODE_CIMMS = MODE_IMMS << MODE_CSHIFT, + MODE_CIMMZ = MODE_IMMZ << MODE_CSHIFT, + + MODE_BCJOINT = (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT), + MODE_BCKI = MODE_KI << MODE_BCSHIFT, + MODE_BCKF = MODE_KF << MODE_BCSHIFT, + MODE_BCKS = MODE_KS << MODE_BCSHIFT, + MODE_BCKP = MODE_KP << MODE_BCSHIFT, + MODE_BCIMMS = MODE_IMMS << MODE_BCSHIFT, + MODE_BCIMMZ = MODE_IMMZ << MODE_BCSHIFT, + MODE_BCPARAM = MODE_PARAM << MODE_BCSHIFT, + MODE_BCTHROW = MODE_THROW << MODE_BCSHIFT, + MODE_BCCATCH = MODE_CATCH << MODE_BCSHIFT, + MODE_BCCAST = MODE_CAST << MODE_BCSHIFT, + + MODE_ABCJOINT = (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT, +}; + +struct VMOpInfo +{ + const char *Name; + int Mode; +}; + +extern const VMOpInfo OpInfo[NUM_OPS]; + + +// VM frame layout: +// VMFrame header +// parameter stack - 16 byte boundary, 16 bytes each +// double registers - 8 bytes each +// string registers - 4 or 8 bytes each +// address registers - 4 or 8 bytes each +// data registers - 4 bytes each +// address register tags-1 byte each +// extra space - 16 byte boundary +struct VMFrame +{ + VMFrame *ParentFrame; + VMFunction *Func; + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UHALF MaxParam; + VM_UHALF NumParam; // current number of parameters + + static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra) + { + int size = (sizeof(VMFrame) + 15) & ~15; + size += numparam * sizeof(VMValue); + size += numregf * sizeof(double); + size += numrega * sizeof(void *); + size += numregs * sizeof(FString); + size += numregd * sizeof(int); + if (numextra != 0) + { + size = (size + 15) & ~15; + size += numextra; + } + return size; + } + + VMValue *GetParam() const + { + assert(((size_t)this & 15) == 0 && "VM frame is unaligned"); + return (VMValue *)(((size_t)(this + 1) + 15) & ~15); + } + + double *GetRegF() const + { + return (double *)(GetParam() + MaxParam); + } + + FString *GetRegS() const + { + return (FString *)(GetRegF() + NumRegF); + } + + void **GetRegA() const + { + return (void **)(GetRegS() + NumRegS); + } + + int *GetRegD() const + { + return (int *)(GetRegA() + NumRegA); + } + + void *GetExtra() const + { + uint8_t *pbeg = (uint8_t*)(GetRegD() + NumRegD); + ptrdiff_t ofs = pbeg - (uint8_t *)this; + return (VM_UBYTE *)this + ((ofs + 15) & ~15); + } + + void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VMValue *¶m) const + { + // Calling the individual functions produces suboptimal code. :( + param = GetParam(); + f = (double *)(param + MaxParam); + s = (FString *)(f + NumRegF); + a = (void **)(s + NumRegS); + d = (int *)(a + NumRegA); + } + + void InitRegS(); +}; + +struct VMRegisters +{ + VMRegisters(const VMFrame *frame) + { + frame->GetAllRegs(d, f, s, a, param); + } + + VMRegisters(const VMRegisters &o) + : d(o.d), f(o.f), s(o.s), a(o.a), param(o.param) + { } + + int *d; + double *f; + FString *s; + void **a; + VMValue *param; +}; + +union FVoidObj +{ + DObject *o; + void *v; +}; + +struct FStatementInfo +{ + uint16_t InstructionIndex; + uint16_t LineNumber; +}; + +class VMFrameStack +{ +public: + VMFrameStack(); + ~VMFrameStack(); + VMFrame *AllocFrame(VMScriptFunction *func); + VMFrame *PopFrame(); + VMFrame *TopFrame() + { + assert(Blocks != NULL && Blocks->LastFrame != NULL); + return Blocks->LastFrame; + } +private: + enum { BLOCK_SIZE = 4096 }; // Default block size + struct BlockHeader + { + BlockHeader *NextBlock; + VMFrame *LastFrame; + VM_UBYTE *FreeSpace; + int BlockSize; + + void InitFreeSpace() + { + FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15); + } + }; + BlockHeader *Blocks; + BlockHeader *UnusedBlocks; + VMFrame *Alloc(int size); +}; + +class VMParamFiller +{ +public: + VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {} + VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {} + + void ParamInt(int val) + { + Reg.d[RegD++] = val; + } + + void ParamFloat(double val) + { + Reg.f[RegF++] = val; + } + + void ParamString(FString &val) + { + Reg.s[RegS++] = val; + } + + void ParamString(const char *val) + { + Reg.s[RegS++] = val; + } + + void ParamObject(DObject *obj) + { + Reg.a[RegA] = obj; + RegA++; + } + + void ParamPointer(void *ptr) + { + Reg.a[RegA] = ptr; + RegA++; + } + +private: + const VMRegisters Reg; + int RegD, RegF, RegS, RegA; +}; + + +enum EVMEngine +{ + VMEngine_Default, + VMEngine_Unchecked, + VMEngine_Checked +}; + +void VMSelectEngine(EVMEngine engine); +extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); +void VMFillParams(VMValue *params, VMFrame *callee, int numparam); + +void VMDumpConstants(FILE *out, const VMScriptFunction *func); +void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); + +extern thread_local VMFrameStack GlobalVMStack; + +typedef std::pair FTypeAndOffset; + +class VMScriptFunction : public VMFunction +{ +public: + VMScriptFunction(FName name = NAME_None); + ~VMScriptFunction(); + void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); + + VMOP *Code; + FStatementInfo *LineInfo; + FString SourceFileName; + int *KonstD; + double *KonstF; + FString *KonstS; + FVoidObj *KonstA; + int ExtraSpace; + int CodeSize; // Size of code in instructions (not bytes) + unsigned LineInfoCount; + unsigned StackSize; + VM_UBYTE NumRegD; + VM_UBYTE NumRegF; + VM_UBYTE NumRegS; + VM_UBYTE NumRegA; + VM_UHALF NumKonstD; + VM_UHALF NumKonstF; + VM_UHALF NumKonstS; + VM_UHALF NumKonstA; + VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once + VM_UBYTE NumArgs; // Number of arguments this function takes + TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction + + void InitExtra(void *addr); + void DestroyExtra(void *addr); + int AllocExtraStack(PType *type); + int PCToLine(const VMOP *pc); +}; diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 50f6568cb..dac907580 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -45,8 +45,6 @@ xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string xx(LS_R, ls, RSRPRI, NOP, 0, 0), xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object xx(LO_R, lo, RPRPRI, NOP, 0, 0), -xx(LOS, los, RPRPKI, LOS_R, 4, REGT_INT), // load object (stack version without read barrier) -xx(LOS_R, lo, RPRPRI, NOP, 0, 0), xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer xx(LP_R, lp, RPRPRI, NOP, 0, 0), xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2 diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index 69b8af3bf..d886c8db2 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -32,6 +32,8 @@ */ #include "dobject.h" +#include "vmintern.h" +#include "types.h" #include "sc_man.h" #include "memarena.h" #include "zcc_parser.h" diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 677b5f11e..1c70e42b9 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -49,6 +49,7 @@ #include "i_system.h" #include "gdtoa.h" #include "backend/vmbuilder.h" +#include "types.h" FSharedStringArena VMStringConstants; bool isActor(PContainerType *type); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index b55fd153b..3c1e55805 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -3,6 +3,7 @@ #include "memarena.h" #include "sc_man.h" +#include "types.h" struct ZCCToken { @@ -193,7 +194,7 @@ struct ZCC_NamedNode : ZCC_TreeNode struct ZCC_Struct : ZCC_NamedNode { - VM_UWORD Flags; + uint32_t Flags; ZCC_TreeNode *Body; PContainerType *Type; VersionInfo Version; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index e00fdae4a..af848cbeb 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -64,6 +64,7 @@ extern void ChildSigHandler (int signum); #include "templates.h" #include "stats.h" #include "timidity/timidity.h" +#include "vm.h" #define GZIP_ID1 31 #define GZIP_ID2 139 diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp index 0658545b3..bde80a431 100644 --- a/src/teaminfo.cpp +++ b/src/teaminfo.cpp @@ -41,6 +41,7 @@ #include "v_font.h" #include "v_video.h" #include "w_wad.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 2bd779865..f7d9a539b 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -53,6 +53,7 @@ #include "r_renderer.h" #include "r_sky.h" #include "textures/textures.h" +#include "vm.h" FTextureManager TexMan; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 5def06068..314a0fb9a 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -62,6 +62,7 @@ #include "r_data/colormaps.h" #include "g_levellocals.h" #include "textures.h" +#include "vm.h" CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) { diff --git a/src/v_font.cpp b/src/v_font.cpp index e6aa57a50..f133b1be4 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -95,6 +95,7 @@ The FON2 header is followed by variable length data: #include "colormatcher.h" #include "v_palette.h" #include "v_text.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/v_text.cpp b/src/v_text.cpp index 454964aa3..3c31312b3 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -47,6 +47,7 @@ #include "doomstat.h" #include "templates.h" #include "gstrings.h" +#include "vm.h" int ListGetInt(VMVa_List &tags); diff --git a/src/v_video.cpp b/src/v_video.cpp index f27c0c499..96b45fad6 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -65,6 +65,7 @@ #include "r_renderer.h" #include "menu/menu.h" #include "r_data/voxels.h" +#include "vm.h" EXTERN_CVAR(Bool, r_blendmethod) diff --git a/src/v_video.h b/src/v_video.h index 1ea7c7bbf..56cb3ee0d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -535,6 +535,7 @@ void V_Init2 (); void V_Shutdown (); class FScanner; +struct FScriptPosition; // Returns the closest color to the one desired. String // should be of the form "rr gg bb". int V_GetColorFromString (const uint32_t *palette, const char *colorstring, FScriptPosition *sc = nullptr); diff --git a/src/virtual.h b/src/virtual.h deleted file mode 100644 index 67d950433..000000000 --- a/src/virtual.h +++ /dev/null @@ -1,30 +0,0 @@ -inline unsigned GetVirtualIndex(PClass *cls, const char *funcname) -{ - // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. - auto sym = dyn_cast(cls->FindSymbol(funcname, false)); - assert(sym != nullptr); - auto VIndex = sym->Variants[0].Implementation->VirtualIndex; - return VIndex; -} - -#define IFVIRTUALPTR(self, cls, funcname) \ - static unsigned VIndex = ~0u; \ - if (VIndex == ~0u) { \ - VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ - assert(VIndex != ~0u); \ - } \ - auto clss = self->GetClass(); \ - VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ - if (func != nullptr) - -#define IFVIRTUAL(cls, funcname) IFVIRTUALPTR(this, cls, funcname) - -#define IFVIRTUALPTRNAME(self, cls, funcname) \ - static unsigned VIndex = ~0u; \ - if (VIndex == ~0u) { \ - VIndex = GetVirtualIndex(PClass::FindClass(cls), #funcname); \ - assert(VIndex != ~0u); \ - } \ - auto clss = self->GetClass(); \ - VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ - if (func != nullptr) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 1f62b15c5..f1e633970 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -57,6 +57,7 @@ #include "resourcefiles/resourcefile.h" #include "md5.h" #include "doomstat.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index f9a49eb0d..dc915a011 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -62,7 +62,7 @@ #include "gstrings.h" #include "cmdlib.h" #include "g_levellocals.h" -#include "virtual.h" +#include "vm.h" CVAR(Bool, wi_percents, true, CVAR_ARCHIVE) CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) @@ -710,7 +710,7 @@ void WI_Ticker() IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Ticker) { VMValue self = WI_Screen; - GlobalVMStack.Call(func, &self, 1, nullptr, 0); + VMCall(func, &self, 1, nullptr, 0); } } } @@ -729,7 +729,7 @@ void WI_Drawer() IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Drawer) { VMValue self = WI_Screen; - GlobalVMStack.Call(func, &self, 1, nullptr, 0); + VMCall(func, &self, 1, nullptr, 0); screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind. // The internal handling here is somewhat poor. After being set to 'LeavingIntermission' @@ -780,7 +780,7 @@ void WI_Start(wbstartstruct_t *wbstartstruct) IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Start) { VMValue val[2] = { WI_Screen, wbstartstruct }; - GlobalVMStack.Call(func, val, 2, nullptr, 0); + VMCall(func, val, 2, nullptr, 0); } GC::AddSoftRoot(WI_Screen); } From 85d8244d036bbeb78f3c987189bb9aa79ae2b55c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 13 Apr 2017 02:18:06 +0200 Subject: [PATCH 24/24] - fixed: With the reorganization of the class data the setup of actor replacements must be delayed until after InitializeDefaults has been called. --- src/scripting/zscript/zcc_compile.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 1c70e42b9..1e4acc9b1 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -745,7 +745,7 @@ void ZCCCompiler::CreateClassTypes() Classes.Push(c); } - // Last but not least: Now that all classes have been created, we can create the symbols for the internal enums and link the treenode symbol tables and set up replacements + // Last but not least: Now that all classes have been created, we can create the symbols for the internal enums and link the treenode symbol tables. for (auto cd : Classes) { for (auto e : cd->Enums) @@ -762,12 +762,6 @@ void ZCCCompiler::CreateClassTypes() break; } } - - if (cd->cls->Replaces != nullptr && !static_cast(cd->ClassType())->SetReplacement(cd->cls->Replaces->Id)) - { - Warn(cd->cls, "Replaced type '%s' not found for %s", FName(cd->cls->Replaces->Id).GetChars(), cd->Type()->TypeName.GetChars()); - } - } } @@ -2201,7 +2195,7 @@ void ZCCCompiler::InitDefaults() // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. if (!c->ClassType()->IsDescendantOf(RUNTIME_CLASS(AActor))) { - if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars()); + if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->ClassType()->TypeName.GetChars()); if (c->ClassType()->ParentClass) { auto ti = static_cast(c->ClassType()); @@ -2228,6 +2222,12 @@ void ZCCCompiler::InitDefaults() ti->InitializeDefaults(); + // Replacements require that the meta data has been allocated by InitializeDefaults. + if (c->cls->Replaces != nullptr && !ti->SetReplacement(c->cls->Replaces->Id)) + { + Warn(c->cls, "Replaced type '%s' not found for %s", FName(c->cls->Replaces->Id).GetChars(), ti->TypeName.GetChars()); + } + // We need special treatment for this one field in AActor's defaults which cannot be made visible to DECORATE as a property. // It's better to do this here under controlled conditions than deeper down in the class type classes. if (ti == RUNTIME_CLASS(AActor))