From 924096694e700b7d8c9678ae8484487487ece845 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 11 Nov 2016 21:52:08 +0100 Subject: [PATCH] - implemented super calls and proper dispatch of scripted virtual overrides for Destroy. --- src/dobject.cpp | 1 + src/dobject.h | 30 +++++++++++++++++-- src/scripting/codegeneration/codegen.cpp | 38 ++++++++++++++++++++++-- src/scripting/codegeneration/codegen.h | 18 +++++++++++ src/scripting/zscript/zcc_compile.cpp | 10 +++++++ 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index e21d07526..6fa7d5317 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -366,6 +366,7 @@ void DObject::Destroy () DEFINE_ACTION_FUNCTION(DObject, Destroy) { PARAM_SELF_PROLOGUE(DObject); + self->VMSuperCall(); self->Destroy(); return 0; } diff --git a/src/dobject.h b/src/dobject.h index 60668ceec..d5e11a04c 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -235,7 +235,6 @@ enum EObjectFlags OF_EuthanizeMe = 1 << 5, // Object wants to die 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_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) OF_WhiteBits = OF_White0 | OF_White1, OF_MarkBits = OF_WhiteBits | OF_Black, @@ -244,6 +243,8 @@ enum EObjectFlags OF_JustSpawned = 1 << 8, // Thinker was spawned this tic OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls 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 TObjPtr; @@ -498,6 +499,11 @@ public: void SerializeUserVars(FSerializer &arc); virtual void Serialize(FSerializer &arc); + void VMSuperCall() + { + ObjectFlags |= OF_SuperCall; + } + void ClearClass() { Class = NULL; @@ -652,7 +658,27 @@ private: public: void Destroy() { - ExportedNatives::Get()->template Destroy(this); + if (ObjectFlags & OF_SuperCall) + { + ObjectFlags &= OF_SuperCall; + ExportedNatives::Get()->template Destroy(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(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() { diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 49b1d6bae..dfe02404b 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1350,7 +1350,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // first deal with the simple types 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; 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); PClass *cls; bool staticonly = false; + bool novirtual = false; if (Self->ExprType == EFX_Identifier) { @@ -6282,6 +6302,15 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& 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()) { // handle builtins: Vectors got 2: Length and Unit. @@ -6349,7 +6378,7 @@ isresolved: // do not pass the self pointer to static functions. 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; delete this; return x->Resolve(ctx); @@ -6971,6 +7000,11 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx) { fail = true; } + if (Expressions[i]->ValueType == TypeError) + { + ScriptPosition.Message(MSG_ERROR, "Invalid statement"); + fail = true; + } } if (fail) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 46d419051..d5f812d52 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -276,6 +276,7 @@ enum EFxType EFX_TypeCheck, EFX_DynamicCast, EFX_GlobalVariable, + EFX_Super, EFX_COUNT }; @@ -1241,6 +1242,23 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxSuper +// +//========================================================================== + +class FxSuper : public FxSelf +{ +public: + FxSuper(const FScriptPosition&pos) + : FxSelf(pos) + { + ExprType = EFX_Super; + } + FxExpression *Resolve(FCompileContext&); +}; + //========================================================================== // // FxArrayElement diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 6c837cead..f52e0e062 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2898,6 +2898,16 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return list; } + case AST_Expression: + { + auto ret = static_cast(ast); + if (ret->Operation == PEX_Super) + { + return new FxSuper(*ast); + } + break; + } + case AST_ExpressionStmt: return ConvertNode(static_cast(ast)->Expression);