diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dcabeb2a0f..a6dcfd766a 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 31961831e0..5c39857dc8 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 637494333c..5fc891fb42 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 1c4230d568..ea80030ffd 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 540c77f7b3..76c552db23 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 4d40ce66d3..b45210053b 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 0d37198f3f..f401ed0e5b 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 f223444e4a..6b0b62da7f 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 ad32fcca97..464ed4495a 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 2b7f6999a8..dcb42a2bba 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 d6edd72302..b03ca3e504 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 74258e3aeb..a476e4b8af 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 ca2a3e32fd..687e76f850 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 18a6f14b5a..b4db0386a7 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 a220e2df68..d7703de1c9 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 dfb362a816..24cd43451f 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 49b4d533f1..3093983318 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 ec257a3101..719fbf2d76 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 af1771c5b8..5144cf56e3 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 970b68da5f..c2ae5f0b40 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 17cd67a7aa..16b818ba79 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 701b98b000..8b2ac54c93 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 0a44e6d14f..5d2617881f 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 e4079121ad..5086d7832c 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 ecde760f33..46248deca6 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 575e7027cd..71f796a89b 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 95e87baf4f..4aaa75fa51 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 f7177165e1..3b68e8c2ba 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 2c41b20990..5c0919820a 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 c414a92752..8ac35da248 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 befd1115bd..6e23c9523a 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 a46911217a..6d9baea244 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 cffe67b114..63c9d9ed85 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 2514cd8d21..1afe8d46df 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 ac4f5117ce..8dea1e577a 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 978dd1696a..e0b065a131 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 7f677bf3a9..7dd40c1ea6 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 01a1a3f471..d167631cf5 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 437e7ff898..b667415a87 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 59b3ad9903..fb50834c06 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 fdca9abc81..f76654165d 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 5f7d4bfe5d..54bc8af07c 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 490f8ec653..5a2f189746 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 a7a69dbb5e..3684209646 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 fa5796a453..55f85c2210 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 b23798727c..5f139f0aff 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 0feb013f41..55dfdd8e67 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 a23316bd15..8fe698a2f6 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 4c2c509e8f..c7bc715f2e 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 08399fe49d..bbd9281b77 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 20579ced46..81a1bc5d62 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 8aed0370e5..6c25bd46d7 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 8f7d935ee5..918419fbea 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 b6bf36a08a..6de00eb378 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 7ac614f2ef..11e520a0dc 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 39b97f1d87..12a29dd3b0 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 d2d98d2377..dd00519e27 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 fc31d60caa..21ed99c619 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 f702606ce9..afaad56e93 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 959dbf2202..12c158c941 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 b64478c77e..f84afb1ff8 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 e91de462ae..08cb7123cc 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 04cb9c9ea2..b4c69d3fe1 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 fcfd0ddf46..43c094e25f 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 fae4e13df9..c358ceed5d 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 748e25ca31..6fe06ed0fc 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 b34b4de1dd..a56e4e790a 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 b044b3066c..717747a8a2 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 ac105f4ee9..94dc1df1d0 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 1506059ea3..81b1d0a904 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 f1f1b31f29..b0cce58ab9 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 acf6e022de..9926f289ec 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 adcbc93fd8..3c61ec4ac7 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 7a5927be61..17abea01e5 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 71cb943f82..8d4652d2bc 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 a767fdcaa7..75f6a68a86 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 7d731eb5fa..0c47493ea0 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 35831c958f..1f6c8baca2 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 0152c65205..2262af154c 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 f227e02406..c426323183 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 d8af3204d4..13f9ecb27d 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 ea5213b66c..d336882766 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 3a37da8e3b..be5390bba3 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 5fc59f7b05..098ecaaa5a 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 649e5584a8..2268bd5ea9 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 14fd218867..bf585077f1 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 d727623b4b..8019a5a411 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 5bbeb92961..3c2b4e3f12 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 0084c319ce..374d8a524f 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 0000000000..b445ad8844 --- /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 0000000000..3c233c6175 --- /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 d05e33a5fb..b7b7aa1c5a 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 1e3afd709e..0bad8c0554 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 a62627cc44..b573c06704 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 c631dea748..69a6febbf4 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 0000000000..e79a2360d4 --- /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 50f6568cb4..dac9075805 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 69b8af3bf9..d886c8db27 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 677b5f11e1..1c70e42b93 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 b55fd153ba..3c1e55805e 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 e00fdae4a9..af848cbeb6 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 0658545b35..bde80a4318 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 2bd7798650..f7d9a539b2 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 5def06068e..314a0fb9af 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 e6aa57a505..f133b1be4f 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 454964aa3f..3c31312b3f 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 f27c0c499a..96b45fad66 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 1ea7c7bbf3..56cb3ee0db 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 67d9504334..0000000000 --- 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 1f62b15c58..f1e6339704 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 f9a49eb0de..dc915a0119 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); }