- 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.
This commit is contained in:
Christoph Oelckers 2017-04-10 15:17:39 +02:00
parent 175e784b67
commit ef77cbd295
11 changed files with 123 additions and 101 deletions

View file

@ -724,7 +724,7 @@ static int CreatePlaySoundFunc(VMFunctionBuilder &buildit, int value1, int value
// misc1 = state, misc2 = probability // misc1 = state, misc2 = probability
static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2) static int CreateRandomJumpFunc(VMFunctionBuilder &buildit, int value1, int value2)
{ // A_Jump { // A_Jump
int statereg = buildit.GetConstantAddress(FindState(value1), ATAG_STATE); int statereg = buildit.GetConstantAddress(FindState(value1));
buildit.EmitParamInt(value2); // maxchance buildit.EmitParamInt(value2); // maxchance
buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, statereg); // jumpto buildit.Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, statereg); // jumpto

View file

@ -200,6 +200,14 @@ protected:
enum { MetaClassNum = CLASSREG_PClass }; enum { MetaClassNum = CLASSREG_PClass };
// Per-instance variables. There are four. // 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: private:
PClass *Class; // This object's type PClass *Class; // This object's type
public: public:

View file

@ -2723,7 +2723,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem)
PARAM_BOOL_DEF (useammo) PARAM_BOOL_DEF (useammo)
PARAM_BOOL_DEF (transfer_translation); PARAM_BOOL_DEF (transfer_translation);
if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); if (numret > 1) ret[1].SetObject(nullptr);
if (missile == NULL) if (missile == NULL)
{ {
@ -2760,7 +2760,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem)
int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0);
bool res = InitSpawnedItem(self, mo, flags); // for an inventory item's use state bool res = InitSpawnedItem(self, mo, flags); // for an inventory item's use state
if (numret > 0) ret[0].SetInt(res); 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); return MIN(numret, 2);
} }
@ -2787,7 +2787,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx)
PARAM_INT_DEF (chance) PARAM_INT_DEF (chance)
PARAM_INT_DEF (tid) PARAM_INT_DEF (tid)
if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); if (numret > 1) ret[1].SetObject(nullptr);
if (missile == NULL) if (missile == NULL)
{ {
@ -2852,7 +2852,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx)
mo->Angles.Yaw = angle; mo->Angles.Yaw = angle;
} }
if (numret > 0) ret[0].SetInt(res); 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); return MIN(numret, 2);
} }
@ -2872,7 +2872,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade)
PARAM_FLOAT_DEF (zvel) PARAM_FLOAT_DEF (zvel)
PARAM_BOOL_DEF (useammo) PARAM_BOOL_DEF (useammo)
if (numret > 1) ret[1].SetPointer(nullptr, ATAG_OBJECT); if (numret > 1) ret[1].SetObject(nullptr);
if (missile == NULL) if (missile == NULL)
{ {
@ -2934,7 +2934,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade)
if (!P_CheckMissileSpawn(bo, self->radius)) bo = nullptr; if (!P_CheckMissileSpawn(bo, self->radius)) bo = nullptr;
if (numret > 0) ret[0].SetInt(true); 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); return MIN(numret, 2);
} }
else else
@ -4363,7 +4363,7 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload)
if (numret > 0) if (numret > 0)
{ {
ret->SetPointer(NULL, ATAG_STATE); ret->SetPointer(NULL);
numret = 1; 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. // Go back to the refire frames, instead of continuing on to the reload frames.
if (numret != 0) if (numret != 0)
{ {
ret->SetPointer(jump, ATAG_STATE); ret->SetPointer(jump);
} }
} }
else else
@ -4903,7 +4903,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
} }
if (numret > 0) if (numret > 0)
{ {
ret[0].SetPointer(NULL, ATAG_STATE); ret[0].SetPointer(NULL);
} }
if (!ref) if (!ref)
@ -5039,7 +5039,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
} }
if (numret > 0) if (numret > 0)
{ {
ret[0].SetPointer(teleport_state, ATAG_STATE); ret[0].SetPointer(teleport_state);
} }
return numret; return numret;
} }
@ -5337,7 +5337,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Warp)
} }
if (numret > 0) if (numret > 0)
{ {
ret[0].SetPointer(NULL, ATAG_STATE); ret[0].SetPointer(NULL);
} }
if ((flags & WARPF_USETID)) 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. // in this case, you have the statejump to help you handle all the success anyway.
if (numret > 0) if (numret > 0)
{ {
ret[0].SetPointer(success_state, ATAG_STATE); ret[0].SetPointer(success_state);
} }
} }
else if (numret > 1) else if (numret > 1)

View file

@ -2054,7 +2054,7 @@ DEFINE_ACTION_FUNCTION(AActor, TestMobjZ)
if (numret > 1) if (numret > 1)
{ {
numret = 2; numret = 2;
ret[1].SetPointer(on, ATAG_OBJECT); ret[1].SetObject(on);
} }
if (numret > 0) if (numret > 0)
{ {
@ -4685,7 +4685,7 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack)
int acdmg; int acdmg;
if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from. 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); 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; if (numret > 1) ret[1].SetInt(acdmg), numret = 2;
return numret; return numret;
} }

View file

@ -7247,8 +7247,8 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPlayerMissile)
AActor *missileactor; AActor *missileactor;
if (numparam == 2) angle = self->Angles.Yaw; if (numparam == 2) angle = self->Angles.Yaw;
AActor *misl = P_SpawnPlayerMissile(self, x, y, z, type, angle, lt, &missileactor, nofreeaim, noautoaim, aimflags); 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 > 0) ret[0].SetObject(misl);
if (numret > 1) ret[1].SetPointer(missileactor, ATAG_OBJECT), numret = 2; if (numret > 1) ret[1].SetObject(missileactor), numret = 2;
return numret; return numret;
} }
@ -7692,7 +7692,7 @@ FDropItem *AActor::GetDropItems() const
DEFINE_ACTION_FUNCTION(AActor, GetDropItems) DEFINE_ACTION_FUNCTION(AActor, GetDropItems)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_OBJECT(self->GetDropItems()); ACTION_RETURN_POINTER(self->GetDropItems());
} }
double AActor::GetGravity() const double AActor::GetGravity() const

View file

@ -112,7 +112,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestFloorSurrounding)
vertex_t *v; vertex_t *v;
double h = self->FindLowestFloorSurrounding(&v); double h = self->FindLowestFloorSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -161,7 +161,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorSurrounding)
vertex_t *v; vertex_t *v;
double h = self->FindHighestFloorSurrounding(&v); double h = self->FindHighestFloorSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -224,7 +224,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestFloor)
vertex_t *v; vertex_t *v;
double h = self->FindNextHighestFloor(&v); double h = self->FindNextHighestFloor(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -286,7 +286,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestFloor)
vertex_t *v; vertex_t *v;
double h = self->FindNextLowestFloor(&v); double h = self->FindNextLowestFloor(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -348,7 +348,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestCeiling)
vertex_t *v; vertex_t *v;
double h = self->FindNextLowestCeiling(&v); double h = self->FindNextLowestCeiling(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -411,7 +411,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestCeiling)
vertex_t *v; vertex_t *v;
double h = self->FindNextHighestCeiling(&v); double h = self->FindNextHighestCeiling(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -459,7 +459,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingSurrounding)
vertex_t *v; vertex_t *v;
double h = self->FindLowestCeilingSurrounding(&v); double h = self->FindLowestCeilingSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -508,7 +508,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestCeilingSurrounding)
vertex_t *v; vertex_t *v;
double h = self->FindHighestCeilingSurrounding(&v); double h = self->FindHighestCeilingSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -744,7 +744,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorPoint)
vertex_t *v; vertex_t *v;
double h = self->FindHighestFloorPoint(&v); double h = self->FindHighestFloorPoint(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -793,7 +793,7 @@ DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingPoint)
vertex_t *v; vertex_t *v;
double h = self->FindLowestCeilingPoint(&v); double h = self->FindLowestCeilingPoint(&v);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -1207,7 +1207,7 @@ DEFINE_ACTION_FUNCTION(_Sector, HighestCeilingAt)
sector_t *s; sector_t *s;
double h = self->HighestCeilingAt(DVector2(x, y), &s); double h = self->HighestCeilingAt(DVector2(x, y), &s);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -1242,7 +1242,7 @@ DEFINE_ACTION_FUNCTION(_Sector, LowestFloorAt)
sector_t *s; sector_t *s;
double h = self->LowestFloorAt(DVector2(x, y), &s); double h = self->LowestFloorAt(DVector2(x, y), &s);
if (numret > 0) ret[0].SetFloat(h); 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; return numret;
} }
@ -1309,12 +1309,12 @@ DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt)
if (numret > 2) if (numret > 2)
{ {
ret[2].SetPointer(resultff, ATAG_GENERIC); ret[2].SetPointer(resultff);
numret = 3; numret = 3;
} }
if (numret > 1) if (numret > 1)
{ {
ret[1].SetPointer(resultsec, ATAG_GENERIC); ret[1].SetPointer(resultsec);
} }
if (numret > 0) if (numret > 0)
{ {
@ -1387,12 +1387,12 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
if (numret > 2) if (numret > 2)
{ {
ret[2].SetPointer(resultff, ATAG_GENERIC); ret[2].SetPointer(resultff);
numret = 3; numret = 3;
} }
if (numret > 1) if (numret > 1)
{ {
ret[1].SetPointer(resultsec, ATAG_GENERIC); ret[1].SetPointer(resultsec);
} }
if (numret > 0) if (numret > 0)
{ {

View file

@ -385,7 +385,7 @@ void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<siz
break; break;
case REGT_POINTER: case REGT_POINTER:
build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0));
break; break;
case REGT_STRING: case REGT_STRING:
@ -588,11 +588,7 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
else if (regtype == REGT_POINTER) else if (regtype == REGT_POINTER)
{ {
VM_ATAG tag = ATAG_GENERIC; VM_ATAG tag = ATAG_GENERIC;
if (value.Type == TypeState) if (value.Type->GetLoadOp() != OP_LP)
{
tag = ATAG_STATE;
}
else if (value.Type->GetLoadOp() != OP_LP)
{ {
tag = ATAG_OBJECT; tag = ATAG_OBJECT;
} }
@ -2998,7 +2994,7 @@ texcheck:
auto * countptr = &ptr->Count; auto * countptr = &ptr->Count;
ExpEmit bndp(build, REGT_POINTER); ExpEmit bndp(build, REGT_POINTER);
ExpEmit bndc(build, REGT_INT); 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_LW, bndc.RegNum, bndp.RegNum, build->GetConstantInt(0));
build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum); build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum);
bndp.Free(build); 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 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); 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) if (min != nullptr && max != nullptr)
{ {
EmitParameter(build, min, ScriptPosition); EmitParameter(build, min, ScriptPosition);
@ -5657,7 +5653,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
assert(((PSymbolVMFunction *)sym)->Function != nullptr); assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function; 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(0);
build->EmitParamInt(choices.Size() - 1); build->EmitParamInt(choices.Size() - 1);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 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 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); 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) if (min != nullptr && max != nullptr)
{ {
EmitParameter(build, min, ScriptPosition); 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 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); 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); EmitParameter(build, mask, ScriptPosition);
build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
@ -6661,7 +6657,7 @@ ExpEmit FxGlobalVariable::Emit(VMFunctionBuilder *build)
{ {
ExpEmit obj(build, REGT_POINTER); 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) if (AddressRequested)
{ {
return obj; return obj;
@ -6744,34 +6740,34 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
switch (CVar->GetRealType()) switch (CVar->GetRealType())
{ {
case CVAR_Int: case CVAR_Int:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FIntCVar *>(CVar)->Value, ATAG_GENERIC)); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FIntCVar *>(CVar)->Value));
build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul);
break; break;
case CVAR_Color: case CVAR_Color:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FColorCVar *>(CVar)->Value, ATAG_GENERIC)); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FColorCVar *>(CVar)->Value));
build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul);
break; break;
case CVAR_Float: case CVAR_Float:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FFloatCVar *>(CVar)->Value, ATAG_GENERIC)); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FFloatCVar *>(CVar)->Value));
build->Emit(OP_LSP, dest.RegNum, addr.RegNum, nul); build->Emit(OP_LSP, dest.RegNum, addr.RegNum, nul);
break; break;
case CVAR_Bool: case CVAR_Bool:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FBoolCVar *>(CVar)->Value, ATAG_GENERIC)); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FBoolCVar *>(CVar)->Value));
build->Emit(OP_LBU, dest.RegNum, addr.RegNum, nul); build->Emit(OP_LBU, dest.RegNum, addr.RegNum, nul);
break; break;
case CVAR_String: case CVAR_String:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FStringCVar *>(CVar)->Value, ATAG_GENERIC)); build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FStringCVar *>(CVar)->Value));
build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul); build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul);
break; break;
case CVAR_DummyBool: case CVAR_DummyBool:
{ {
auto cv = static_cast<FFlagCVar *>(CVar); auto cv = static_cast<FFlagCVar *>(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_LW, dest.RegNum, addr.RegNum, nul);
build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum);
build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1)); build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1));
@ -6781,7 +6777,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
case CVAR_DummyInt: case CVAR_DummyInt:
{ {
auto cv = static_cast<FMaskCVar *>(CVar); auto cv = static_cast<FMaskCVar *>(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_LW, dest.RegNum, addr.RegNum, nul);
build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(cv->BitVal)); build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(cv->BitVal));
build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); 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. // 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, 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; count += 2;
} }
@ -10690,9 +10686,9 @@ int BuiltinNameToClass(VMValue *param, TArray<VMValue> &defaultparam, int numpar
// Let the caller check this. Making this an error with a message is only taking away options from the user. // Let the caller check this. Making this an error with a message is only taking away options from the user.
cls = nullptr; cls = nullptr;
} }
ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT); ret->SetObject(const_cast<PClass *>(cls));
} }
else ret->SetPointer(nullptr, ATAG_OBJECT); else ret->SetObject(nullptr);
return 1; return 1;
} }

View file

@ -51,7 +51,7 @@ public:
// Returns the constant register holding the value. // Returns the constant register holding the value.
unsigned GetConstantInt(int val); unsigned GetConstantInt(int val);
unsigned GetConstantFloat(double 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 GetConstantString(FString str);
unsigned AllocConstantsInt(unsigned int count, int *values); unsigned AllocConstantsInt(unsigned int count, int *values);

View file

@ -181,20 +181,6 @@ enum
{ {
ATAG_GENERIC, // pointer to something; we don't care what ATAG_GENERIC, // pointer to something; we don't care what
ATAG_OBJECT, // pointer to an object; will be followed by GC 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 enum EVMAbortException
@ -366,6 +352,7 @@ struct VMReturn
assert(RegType == REGT_STRING); assert(RegType == REGT_STRING);
*(FString *)Location = val; *(FString *)Location = val;
} }
void SetPointer(void *val, int tag) void SetPointer(void *val, int tag)
{ {
assert(RegType == REGT_POINTER); 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) void IntAt(int *loc)
{ {
Location = loc; Location = loc;
@ -852,8 +859,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
// variable name <x> at position <p> // variable name <x> at position <p>
void NullParam(const char *varname); void NullParam(const char *varname);
#ifdef _DEBUG
bool AssertObject(void * ob);
#endif
#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr) #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. // 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_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; #define PARAM_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_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_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_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_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 && (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_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_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_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 && (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_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 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_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; } #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; 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_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, ATAG_GENERIC); 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->SetPointer(state, ATAG_OBJECT); 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_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_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) #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)

View file

@ -82,7 +82,6 @@ void ThrowVMException(VMException *x);
#define ASSERTF(x) assert((unsigned)(x) < f->NumRegF) #define ASSERTF(x) assert((unsigned)(x) < f->NumRegF)
#define ASSERTA(x) assert((unsigned)(x) < f->NumRegA) #define ASSERTA(x) assert((unsigned)(x) < f->NumRegA)
#define ASSERTS(x) assert((unsigned)(x) < f->NumRegS) #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 ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD)
#define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) #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

View file

@ -110,13 +110,13 @@ begin:
NEXTOP; NEXTOP;
OP(CLSS): 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.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; reg.atag[a] = ATAG_OBJECT;
NEXTOP; NEXTOP;
OP(META): 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.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; reg.atag[a] = ATAG_OBJECT;
NEXTOP; NEXTOP;
@ -657,7 +657,6 @@ begin:
OP(CALL_K): OP(CALL_K):
ASSERTKA(a); ASSERTKA(a);
assert(konstatag[a] == ATAG_OBJECT);
ptr = konsta[a].o; ptr = konsta[a].o;
goto Do_CALL; goto Do_CALL;
OP(CALL): OP(CALL):
@ -713,7 +712,6 @@ begin:
NEXTOP; NEXTOP;
OP(TAIL_K): OP(TAIL_K):
ASSERTKA(a); ASSERTKA(a);
assert(konstatag[a] == ATAG_OBJECT);
ptr = konsta[a].o; ptr = konsta[a].o;
goto Do_TAILCALL; goto Do_TAILCALL;
OP(TAIL): OP(TAIL):
@ -851,7 +849,7 @@ begin:
else if (a == 1) else if (a == 1)
{ {
ASSERTKA(B); ASSERTKA(B);
assert(konstatag[B] == ATAG_OBJECT); assert(AssertObject(konsta[B].o));
ThrowVMException((VMException *)konsta[B].o); ThrowVMException((VMException *)konsta[B].o);
} }
else else
@ -1709,7 +1707,6 @@ begin:
{ {
assert(pc->a == 3); assert(pc->a == 3);
ASSERTKA(b); ASSERTKA(b);
assert(konstatag[b] == ATAG_OBJECT);
type = (PClass *)konsta[b].o; type = (PClass *)konsta[b].o;
} }
ASSERTA(pc->c); ASSERTA(pc->c);
@ -1831,16 +1828,7 @@ static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int c
{ {
ASSERTS(a); ASSERTA(b); ASSERTS(a); ASSERTA(b);
if (reg.a[b] == nullptr) reg.s[a] = "null"; if (reg.a[b] == nullptr) reg.s[a] = "null";
else if (reg.atag[b] == ATAG_OBJECT) else reg.s[a].Format("%p", reg.a[b]);
{
auto op = static_cast<DObject*>(reg.a[b]);
if (op->IsKindOf(RUNTIME_CLASS(PClass))) reg.s[a].Format("Class<%s>", static_cast<PClass*>(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]);
}
break; break;
} }