- implemented super calls and proper dispatch of scripted virtual overrides for Destroy.

This commit is contained in:
Christoph Oelckers 2016-11-11 21:52:08 +01:00
parent 72e77a6c65
commit 924096694e
5 changed files with 93 additions and 4 deletions

View file

@ -366,6 +366,7 @@ void DObject::Destroy ()
DEFINE_ACTION_FUNCTION(DObject, Destroy) DEFINE_ACTION_FUNCTION(DObject, Destroy)
{ {
PARAM_SELF_PROLOGUE(DObject); PARAM_SELF_PROLOGUE(DObject);
self->VMSuperCall();
self->Destroy(); self->Destroy();
return 0; return 0;
} }

View file

@ -235,7 +235,6 @@ enum EObjectFlags
OF_EuthanizeMe = 1 << 5, // Object wants to die OF_EuthanizeMe = 1 << 5, // Object wants to die
OF_Cleanup = 1 << 6, // Object is now being deleted by the collector OF_Cleanup = 1 << 6, // Object is now being deleted by the collector
OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_WhiteBits = OF_White0 | OF_White1, OF_WhiteBits = OF_White0 | OF_White1,
OF_MarkBits = OF_WhiteBits | OF_Black, OF_MarkBits = OF_WhiteBits | OF_Black,
@ -244,6 +243,8 @@ enum EObjectFlags
OF_JustSpawned = 1 << 8, // Thinker was spawned this tic OF_JustSpawned = 1 << 8, // Thinker was spawned this tic
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_SuperCall = 1 << 12, // A super call from the VM is about to be performed
}; };
template<class T> class TObjPtr; template<class T> class TObjPtr;
@ -498,6 +499,11 @@ public:
void SerializeUserVars(FSerializer &arc); void SerializeUserVars(FSerializer &arc);
virtual void Serialize(FSerializer &arc); virtual void Serialize(FSerializer &arc);
void VMSuperCall()
{
ObjectFlags |= OF_SuperCall;
}
void ClearClass() void ClearClass()
{ {
Class = NULL; Class = NULL;
@ -652,8 +658,28 @@ private:
public: public:
void Destroy() void Destroy()
{ {
if (ObjectFlags & OF_SuperCall)
{
ObjectFlags &= OF_SuperCall;
ExportedNatives<T>::Get()->template Destroy<void, T>(this); ExportedNatives<T>::Get()->template Destroy<void, T>(this);
} }
else
{
static int VIndex = -1;
if (VIndex < 0)
{
// 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<PFunction>(RUNTIME_CLASS(DObject)->Symbols.FindSymbol("Destroy", false));
assert(sym != nullptr);
VIndex = sym->Variants[0].Implementation->VirtualIndex;
assert(VIndex >= 0);
}
// Without the type cast this picks the 'void *' assignment...
VMValue params[1] = { (DObject*)this };
VMFrameStack stack;
stack.Call(GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr);
}
}
void Tick() void Tick()
{ {
ExportedNatives<T>::Get()->template Tick<void, T>(this); ExportedNatives<T>::Get()->template Tick<void, T>(this);

View file

@ -1350,7 +1350,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
// first deal with the simple types // first deal with the simple types
if (ValueType == TypeError || basex->ValueType == TypeError) if (ValueType == TypeError || basex->ValueType == TypeError)
{ {
ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type. This error message means that somewhere in the script compiler an error check is missing."); ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type.");
delete this; delete this;
return nullptr; return nullptr;
} }
@ -5433,6 +5433,25 @@ ExpEmit FxSelf::Emit(VMFunctionBuilder *build)
} }
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxSuper::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (ctx.Function == nullptr || ctx.Function->Variants[0].SelfClass == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "super used outside of a member function");
delete this;
return nullptr;
}
ValueType = TypeError; // this intentionally resolves to an invalid type so that it cannot be used outside of super calls.
return this;
}
//========================================================================== //==========================================================================
// //
// //
@ -6268,6 +6287,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
ABORT(ctx.Class); ABORT(ctx.Class);
PClass *cls; PClass *cls;
bool staticonly = false; bool staticonly = false;
bool novirtual = false;
if (Self->ExprType == EFX_Identifier) if (Self->ExprType == EFX_Identifier)
{ {
@ -6282,6 +6302,15 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
} }
SAFE_RESOLVE(Self, ctx); SAFE_RESOLVE(Self, ctx);
if (Self->ExprType == EFX_Super)
{
// give the node the proper value type now that we know it's properly used.
cls = ctx.Function->Variants[0].SelfClass->ParentClass;
Self->ValueType = NewPointer(cls);
Self->ExprType = EFX_Self;
novirtual = true; // super calls are always non-virtual
}
if (Self->IsVector()) if (Self->IsVector())
{ {
// handle builtins: Vectors got 2: Length and Unit. // handle builtins: Vectors got 2: Length and Unit.
@ -6349,7 +6378,7 @@ isresolved:
// do not pass the self pointer to static functions. // do not pass the self pointer to static functions.
auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr; auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr;
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly); auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual);
if (Self == self) Self = nullptr; if (Self == self) Self = nullptr;
delete this; delete this;
return x->Resolve(ctx); return x->Resolve(ctx);
@ -6971,6 +7000,11 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx)
{ {
fail = true; fail = true;
} }
if (Expressions[i]->ValueType == TypeError)
{
ScriptPosition.Message(MSG_ERROR, "Invalid statement");
fail = true;
}
} }
if (fail) if (fail)
{ {

View file

@ -276,6 +276,7 @@ enum EFxType
EFX_TypeCheck, EFX_TypeCheck,
EFX_DynamicCast, EFX_DynamicCast,
EFX_GlobalVariable, EFX_GlobalVariable,
EFX_Super,
EFX_COUNT EFX_COUNT
}; };
@ -1241,6 +1242,23 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
//==========================================================================
//
// FxSuper
//
//==========================================================================
class FxSuper : public FxSelf
{
public:
FxSuper(const FScriptPosition&pos)
: FxSelf(pos)
{
ExprType = EFX_Super;
}
FxExpression *Resolve(FCompileContext&);
};
//========================================================================== //==========================================================================
// //
// FxArrayElement // FxArrayElement

View file

@ -2898,6 +2898,16 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
return list; return list;
} }
case AST_Expression:
{
auto ret = static_cast<ZCC_Expression *>(ast);
if (ret->Operation == PEX_Super)
{
return new FxSuper(*ast);
}
break;
}
case AST_ExpressionStmt: case AST_ExpressionStmt:
return ConvertNode(static_cast<ZCC_ExpressionStmt *>(ast)->Expression); return ConvertNode(static_cast<ZCC_ExpressionStmt *>(ast)->Expression);