From ef77cbd295b8848c919789002c79c5618fda2551 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 10 Apr 2017 15:17:39 +0200 Subject: [PATCH] - stop using the ATAGs for checking pointer types in asserts. This is an incredibly costly way to do a debug check as it infests the entire VM design from top to bottom. These tags are basically useless for anything else but validating object pointers being passed to native functions (i.e. mismatches between definition and declaration) and that simply does not justify a feature that costs execution time in non-debug builds and added memory overhead everywhere. Note that this commit does not remove the tags, it only discontinues their use. --- src/d_dehacked.cpp | 2 +- src/dobject.h | 8 ++++ src/p_actionfunctions.cpp | 24 ++++++------ src/p_map.cpp | 4 +- src/p_mobj.cpp | 6 +-- src/p_sectors.cpp | 32 +++++++-------- src/scripting/backend/codegen.cpp | 40 +++++++++---------- src/scripting/backend/vmbuilder.h | 2 +- src/scripting/vm/vm.h | 65 ++++++++++++++++++------------- src/scripting/vm/vmexec.cpp | 21 +++++++++- src/scripting/vm/vmexec.h | 20 ++-------- 11 files changed, 123 insertions(+), 101 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 69b7c814a..ab3f009e7 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -724,7 +724,7 @@ static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value // misc1 = state, misc2 = probability static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2) { // A_Jump - int statereg = buildit.GetConstantAddress(FindState(value1), ATAG_STATE); + int statereg = buildit.GetConstantAddress(FindState(value1)); buildit.EmitParamInt(value2); // maxchance buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, statereg); // jumpto diff --git a/src/dobject.h b/src/dobject.h index f12bfc501..18a6f14b5 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -200,6 +200,14 @@ protected: enum { MetaClassNum = CLASSREG_PClass }; // Per-instance variables. There are four. +#ifdef _DEBUG +public: + enum + { + MAGIC_ID = 0x1337cafe + }; + uint32_t MagicID = MAGIC_ID; // only used by the VM for checking native function parameter types. +#endif private: PClass *Class; // This object's type public: diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 055274d3d..1b2c0b3db 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -2723,7 +2723,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem) PARAM_BOOL_DEF (useammo) PARAM_BOOL_DEF (transfer_translation); - if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(nullptr); if (missile == NULL) { @@ -2760,7 +2760,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem) int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); bool res = InitSpawnedItem(self, mo, flags); // for an inventory item's use state if (numret > 0) ret[0].SetInt(res); - if (numret > 1) ret[1].SetPointer(mo, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(mo); return MIN(numret, 2); } @@ -2787,7 +2787,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx) PARAM_INT_DEF (chance) PARAM_INT_DEF (tid) - if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(nullptr); if (missile == NULL) { @@ -2852,7 +2852,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx) mo->Angles.Yaw = angle; } if (numret > 0) ret[0].SetInt(res); - if (numret > 1) ret[1].SetPointer(mo, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(mo); return MIN(numret, 2); } @@ -2872,7 +2872,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade) PARAM_FLOAT_DEF (zvel) PARAM_BOOL_DEF (useammo) - if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(nullptr); if (missile == NULL) { @@ -2934,7 +2934,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade) if (!P_CheckMissileSpawn(bo, self->radius)) bo = nullptr; if (numret > 0) ret[0].SetInt(true); - if (numret > 1) ret[1].SetPointer(bo, ATAG_OBJECT); + if (numret > 1) ret[1].SetObject(bo); return MIN(numret, 2); } else @@ -4363,7 +4363,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload) if (numret > 0) { - ret->SetPointer(NULL, ATAG_STATE); + ret->SetPointer(NULL); numret = 1; } @@ -4381,7 +4381,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload) // Go back to the refire frames, instead of continuing on to the reload frames. if (numret != 0) { - ret->SetPointer(jump, ATAG_STATE); + ret->SetPointer(jump); } } else @@ -4903,7 +4903,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport) } if (numret > 0) { - ret[0].SetPointer(NULL, ATAG_STATE); + ret[0].SetPointer(NULL); } if (!ref) @@ -5039,7 +5039,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport) } if (numret > 0) { - ret[0].SetPointer(teleport_state, ATAG_STATE); + ret[0].SetPointer(teleport_state); } return numret; } @@ -5337,7 +5337,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp) } if (numret > 0) { - ret[0].SetPointer(NULL, ATAG_STATE); + ret[0].SetPointer(NULL); } if ((flags & WARPF_USETID)) @@ -5363,7 +5363,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp) // in this case, you have the statejump to help you handle all the success anyway. if (numret > 0) { - ret[0].SetPointer(success_state, ATAG_STATE); + ret[0].SetPointer(success_state); } } else if (numret > 1) diff --git a/src/p_map.cpp b/src/p_map.cpp index 6f3f01cf4..d2d98d237 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2054,7 +2054,7 @@ DEFINE_ACTION_FUNCTION(AActor, TestMobjZ) if (numret > 1) { numret = 2; - ret[1].SetPointer(on, ATAG_OBJECT); + ret[1].SetObject(on); } if (numret > 0) { @@ -4685,7 +4685,7 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack) int acdmg; if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from. auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg); - if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT); + if (numret > 0) ret[0].SetObject(puff); if (numret > 1) ret[1].SetInt(acdmg), numret = 2; return numret; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 08a2f922f..6a543f091 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7247,8 +7247,8 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPlayerMissile) AActor *missileactor; if (numparam == 2) angle = self->Angles.Yaw; AActor *misl = P_SpawnPlayerMissile(self, x, y, z, type, angle, lt, &missileactor, nofreeaim, noautoaim, aimflags); - if (numret > 0) ret[0].SetPointer(misl, ATAG_OBJECT); - if (numret > 1) ret[1].SetPointer(missileactor, ATAG_OBJECT), numret = 2; + if (numret > 0) ret[0].SetObject(misl); + if (numret > 1) ret[1].SetObject(missileactor), numret = 2; return numret; } @@ -7692,7 +7692,7 @@ FDropItem *AActor::GetDropItems() const DEFINE_ACTION_FUNCTION(AActor, GetDropItems) { PARAM_SELF_PROLOGUE(AActor); - ACTION_RETURN_OBJECT(self->GetDropItems()); + ACTION_RETURN_POINTER(self->GetDropItems()); } double AActor::GetGravity() const diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 7dac68e1a..b64478c77 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -112,7 +112,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestFloorSurrounding) vertex_t *v; double h = self->FindLowestFloorSurrounding(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -161,7 +161,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorSurrounding) vertex_t *v; double h = self->FindHighestFloorSurrounding(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -224,7 +224,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestFloor) vertex_t *v; double h = self->FindNextHighestFloor(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -286,7 +286,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestFloor) vertex_t *v; double h = self->FindNextLowestFloor(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -348,7 +348,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestCeiling) vertex_t *v; double h = self->FindNextLowestCeiling(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -411,7 +411,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestCeiling) vertex_t *v; double h = self->FindNextHighestCeiling(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -459,7 +459,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingSurrounding) vertex_t *v; double h = self->FindLowestCeilingSurrounding(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -508,7 +508,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestCeilingSurrounding) vertex_t *v; double h = self->FindHighestCeilingSurrounding(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -744,7 +744,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorPoint) vertex_t *v; double h = self->FindHighestFloorPoint(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -793,7 +793,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingPoint) vertex_t *v; double h = self->FindLowestCeilingPoint(&v); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(v, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(v); return numret; } @@ -1207,7 +1207,7 @@ DEFINE_ACTION_FUNCTION(_Sector, HighestCeilingAt) sector_t *s; double h = self->HighestCeilingAt(DVector2(x, y), &s); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(s, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(s); return numret; } @@ -1242,7 +1242,7 @@ DEFINE_ACTION_FUNCTION(_Sector, LowestFloorAt) sector_t *s; double h = self->LowestFloorAt(DVector2(x, y), &s); if (numret > 0) ret[0].SetFloat(h); - if (numret > 1) ret[1].SetPointer(s, ATAG_GENERIC); + if (numret > 1) ret[1].SetPointer(s); return numret; } @@ -1309,12 +1309,12 @@ DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt) if (numret > 2) { - ret[2].SetPointer(resultff, ATAG_GENERIC); + ret[2].SetPointer(resultff); numret = 3; } if (numret > 1) { - ret[1].SetPointer(resultsec, ATAG_GENERIC); + ret[1].SetPointer(resultsec); } if (numret > 0) { @@ -1387,12 +1387,12 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) if (numret > 2) { - ret[2].SetPointer(resultff, ATAG_GENERIC); + ret[2].SetPointer(resultff); numret = 3; } if (numret > 1) { - ret[1].SetPointer(resultsec, ATAG_GENERIC); + ret[1].SetPointer(resultsec); } if (numret > 0) { diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 93fca44ed..656fe3ec5 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -385,7 +385,7 @@ void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArrayEmit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); + build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0)); break; case REGT_STRING: @@ -588,11 +588,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) else if (regtype == REGT_POINTER) { VM_ATAG tag = ATAG_GENERIC; - if (value.Type == TypeState) - { - tag = ATAG_STATE; - } - else if (value.Type->GetLoadOp() != OP_LP) + if (value.Type->GetLoadOp() != OP_LP) { tag = ATAG_OBJECT; } @@ -2998,7 +2994,7 @@ texcheck: auto * countptr = &ptr->Count; ExpEmit bndp(build, REGT_POINTER); ExpEmit bndc(build, REGT_INT); - build->Emit(OP_LKP, bndp.RegNum, build->GetConstantAddress(countptr, ATAG_GENERIC)); + build->Emit(OP_LKP, bndp.RegNum, build->GetConstantAddress(countptr)); build->Emit(OP_LW, bndc.RegNum, bndp.RegNum, build->GetConstantInt(0)); build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum); bndp.Free(build); @@ -5536,7 +5532,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); if (min != nullptr && max != nullptr) { EmitParameter(build, min, ScriptPosition); @@ -5657,7 +5653,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); build->EmitParamInt(0); build->EmitParamInt(choices.Size() - 1); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); @@ -5787,7 +5783,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); if (min != nullptr && max != nullptr) { EmitParameter(build, min, ScriptPosition); @@ -5882,7 +5878,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); EmitParameter(build, mask, ScriptPosition); build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); @@ -6661,7 +6657,7 @@ ExpEmit FxGlobalVariable::Emit(VMFunctionBuilder *build) { ExpEmit obj(build, REGT_POINTER); - build->Emit(OP_LKP, obj.RegNum, build->GetConstantAddress((void*)(intptr_t)membervar->Offset, ATAG_GENERIC)); + build->Emit(OP_LKP, obj.RegNum, build->GetConstantAddress((void*)(intptr_t)membervar->Offset)); if (AddressRequested) { return obj; @@ -6744,34 +6740,34 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) switch (CVar->GetRealType()) { case CVAR_Int: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); break; case CVAR_Color: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); break; case CVAR_Float: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); build->Emit(OP_LSP, dest.RegNum, addr.RegNum, nul); break; case CVAR_Bool: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); build->Emit(OP_LBU, dest.RegNum, addr.RegNum, nul); break; case CVAR_String: - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value)); build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul); break; case CVAR_DummyBool: { auto cv = static_cast(CVar); - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value)); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1)); @@ -6781,7 +6777,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build) case CVAR_DummyInt: { auto cv = static_cast(CVar); - build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value)); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(cv->BitVal)); build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); @@ -8967,7 +8963,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { // pass self as stateowner, otherwise all attempts of the subfunction to retrieve a state from a name would fail. build->Emit(OP_PARAM, 0, selfemit.RegType, selfemit.RegNum); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr, ATAG_GENERIC)); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr)); } count += 2; } @@ -10690,9 +10686,9 @@ int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numpar // Let the caller check this. Making this an error with a message is only taking away options from the user. cls = nullptr; } - ret->SetPointer(const_cast(cls), ATAG_OBJECT); + ret->SetObject(const_cast(cls)); } - else ret->SetPointer(nullptr, ATAG_OBJECT); + else ret->SetObject(nullptr); return 1; } diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index a5274794a..1f318a7e5 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -51,7 +51,7 @@ public: // Returns the constant register holding the value. unsigned GetConstantInt(int val); unsigned GetConstantFloat(double val); - unsigned GetConstantAddress(void *ptr, VM_ATAG tag); + unsigned GetConstantAddress(void *ptr, VM_ATAG tag = ATAG_GENERIC); unsigned GetConstantString(FString str); unsigned AllocConstantsInt(unsigned int count, int *values); diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index b95be74e3..6ceb8583d 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -181,20 +181,6 @@ enum { ATAG_GENERIC, // pointer to something; we don't care what ATAG_OBJECT, // pointer to an object; will be followed by GC - - // The following are all for documentation during debugging and are - // functionally no different than ATAG_GENERIC (meaning they are useless because they trigger asserts all over the place.) - - /* - ATAG_FRAMEPOINTER, // pointer to extra stack frame space for this function - ATAG_DREGISTER, // pointer to a data register - ATAG_FREGISTER, // pointer to a float register - ATAG_SREGISTER, // pointer to a string register - ATAG_AREGISTER, // pointer to an address register - */ - - ATAG_RNG, // pointer to FRandom - ATAG_STATE = ATAG_GENERIC, // pointer to FState (cannot have its own type because there's no means to track inside the VM.) }; enum EVMAbortException @@ -366,6 +352,7 @@ struct VMReturn assert(RegType == REGT_STRING); *(FString *)Location = val; } + void SetPointer(void *val, int tag) { assert(RegType == REGT_POINTER); @@ -376,6 +363,26 @@ struct VMReturn } } + void SetPointer(void *val) + { + assert(RegType == REGT_POINTER); + *(void **)Location = val; + if (TagOfs != 0) + { + *((VM_ATAG *)Location + TagOfs) = ATAG_GENERIC; + } + } + + void SetObject(DObject *val) + { + assert(RegType == REGT_POINTER); + *(void **)Location = val; + if (TagOfs != 0) + { + *((VM_ATAG *)Location + TagOfs) = ATAG_OBJECT; + } + } + void IntAt(int *loc) { Location = loc; @@ -852,8 +859,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction // variable name at position

void NullParam(const char *varname); +#ifdef _DEBUG +bool AssertObject(void * ob); +#endif + #define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr) +#define ASSERTINT(p) assert((p).Type == REGT_INT) +#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) +#define ASSERTSTRING(p) assert((p).Type == REGT_STRING) +#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && AssertObject(p.a)) +#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER) + // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; #define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; @@ -868,19 +885,13 @@ void NullParam(const char *varname); #define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a; -#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); -#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); #define PARAM_EXISTS(p) ((p) < numparam) -#define ASSERTINT(p) assert((p).Type == REGT_INT) -#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) -#define ASSERTSTRING(p) assert((p).Type == REGT_STRING) -#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && ((p).atag == ATAG_OBJECT || (p).a == nullptr)) -#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER && (p).atag == ATAG_GENERIC) -#define ASSERTSTATE(p) assert((p).Type == REGT_POINTER && ((p).atag == ATAG_GENERIC || (p).atag == ATAG_STATE)) #define PARAM_INT_DEF_AT(p,x) int x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = param[p].i; } else { ASSERTINT(defaultparam[p]); x = defaultparam[p].i; } #define PARAM_BOOL_DEF_AT(p,x) bool x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = !!param[p].i; } else { ASSERTINT(defaultparam[p]); x = !!defaultparam[p].i; } @@ -1030,9 +1041,9 @@ struct AFuncDesc class AActor; -#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) -#define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_GENERIC); return 1; } return 0; } while(0) -#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0) +#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) +#define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) +#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetObject(state); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) #define ACTION_RETURN_VEC3(v) do { DVector3 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector(u); return 1; } return 0; } while(0) diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index f8fb4bfd2..8d6c188f0 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -82,7 +82,6 @@ void ThrowVMException(VMException *x); #define ASSERTF(x) assert((unsigned)(x) < f->NumRegF) #define ASSERTA(x) assert((unsigned)(x) < f->NumRegA) #define ASSERTS(x) assert((unsigned)(x) < f->NumRegS) -#define ASSERTO(x) assert((unsigned)(x) < f->NumRegA && reg.atag[x] == ATAG_OBJECT) #define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD) #define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) @@ -235,3 +234,23 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } +#ifdef _DEBUG +bool AssertObject(void * ob) +{ + auto obj = (DObject*)ob; + if (obj == nullptr) return true; +#ifdef _MSC_VER + __try + { + return obj->MagicID == DObject::MAGIC_ID; + } + __except (1) + { + return false; + } +#else + // No SEH on non-Microsoft compilers. :( + return obj->MagicID == DObject::MAGIC_ID; +#endif +} +#endif diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 672dfe8ca..1147bb1b6 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -110,13 +110,13 @@ begin: NEXTOP; OP(CLSS): - ASSERTA(a); ASSERTO(B); + ASSERTA(a); ASSERTA(B); reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... reg.atag[a] = ATAG_OBJECT; NEXTOP; OP(META): - ASSERTA(a); ASSERTO(B); + ASSERTA(a); ASSERTA(B); reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... reg.atag[a] = ATAG_OBJECT; NEXTOP; @@ -657,7 +657,6 @@ begin: OP(CALL_K): ASSERTKA(a); - assert(konstatag[a] == ATAG_OBJECT); ptr = konsta[a].o; goto Do_CALL; OP(CALL): @@ -713,7 +712,6 @@ begin: NEXTOP; OP(TAIL_K): ASSERTKA(a); - assert(konstatag[a] == ATAG_OBJECT); ptr = konsta[a].o; goto Do_TAILCALL; OP(TAIL): @@ -851,7 +849,7 @@ begin: else if (a == 1) { ASSERTKA(B); - assert(konstatag[B] == ATAG_OBJECT); + assert(AssertObject(konsta[B].o)); ThrowVMException((VMException *)konsta[B].o); } else @@ -1709,7 +1707,6 @@ begin: { assert(pc->a == 3); ASSERTKA(b); - assert(konstatag[b] == ATAG_OBJECT); type = (PClass *)konsta[b].o; } ASSERTA(pc->c); @@ -1831,16 +1828,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c { ASSERTS(a); ASSERTA(b); if (reg.a[b] == nullptr) reg.s[a] = "null"; - else if (reg.atag[b] == ATAG_OBJECT) - { - auto op = static_cast(reg.a[b]); - if (op->IsKindOf(RUNTIME_CLASS(PClass))) reg.s[a].Format("Class<%s>", static_cast(op)->TypeName.GetChars()); - else reg.s[a].Format("Object<%p>", ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars()); - } - else - { - reg.s[a].Format("%s<%p>", "Pointer", reg.a[b]); - } + else reg.s[a].Format("%p", reg.a[b]); break; }