diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index bcaa374c2..1b1672545 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -89,37 +89,6 @@ static const FLOP FxFlops[] = { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, }; - -//========================================================================== -// -// [ZZ] Magic methods to be used in vmexec.h for runtime checking of scope -// -//========================================================================== - -// this can be imported in vmexec.h -void FScopeBarrier_ValidateNew(PClass* cls, PFunction* callingfunc) -{ - int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; - if (outerside == FScopeBarrier::Side_Virtual) - outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); - int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); - if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" - ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); -} -// this can be imported in vmexec.h -void FScopeBarrier_ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype) -{ - // [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual. - int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; - if (outerside == FScopeBarrier::Side_Virtual) - outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); - int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags); - if (innerside == FScopeBarrier::Side_Virtual) - innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); - if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) - ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside)); -} - //========================================================================== // // FCompileContext diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index fda9de3c3..ad104f317 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -1,5 +1,5 @@ -#include "scopebarrier.h" #include "dobject.h" +#include "scopebarrier.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. @@ -171,3 +171,27 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) if (name) callerror.Format("Can't call %s function %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom)); } } + +// these are for vmexec.h +void FScopeBarrier::ValidateNew(PClass* cls, PFunction* callingfunc) +{ + int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; + if (outerside == FScopeBarrier::Side_Virtual) + outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); + int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags); + if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context" + ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside)); +} +// this can be imported in vmexec.h +void FScopeBarrier::ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype) +{ + // [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual. + int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual; + if (outerside == FScopeBarrier::Side_Virtual) + outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags); + int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags); + if (innerside == FScopeBarrier::Side_Virtual) + innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags); + if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) + ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside)); +} \ No newline at end of file diff --git a/src/scripting/backend/scopebarrier.h b/src/scripting/backend/scopebarrier.h index 514db7a97..db8a5044a 100644 --- a/src/scripting/backend/scopebarrier.h +++ b/src/scripting/backend/scopebarrier.h @@ -51,5 +51,9 @@ struct FScopeBarrier // This is used for comparing a.b.c.d access - if non-allowed field is seen anywhere in the chain, anything after it is non-allowed. // This struct is used so that the logic is in a single place. void AddFlags(int flags1, int flags2, const char* name); + + // this is called from vmexec.h + static void ValidateNew(PClass* cls, PFunction* callingfunc); + static void ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype); }; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 6c66c7b85..02f048a1c 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -7,11 +7,8 @@ #include "cmdlib.h" #include "doomerrors.h" #include "memarena.h" +#include "scripting/backend/scopebarrier.h" -// [ZZ] there are serious circular references between this and the rest of ZScript code, so it needs to be done like this -// these are used in vmexec.h -void FScopeBarrier_ValidateNew(PClass* cls, PFunction* callingfunc); -void FScopeBarrier_ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype); class DObject; extern FMemArena ClassDataAllocator; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index cdf598649..0281be3df 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -673,7 +673,7 @@ begin: PFunction* callingfunc = (PFunction*)(reg.param + f->NumParam - b)[1].a; DObject* dobj = (DObject*)(reg.param + f->NumParam - b)[2].a; // this is the self pointer. it should be in, since Side_Virtual functions are always non-static methods. PClass* selftype = dobj->GetClass(); - FScopeBarrier_ValidateCall(calledfunc, callingfunc, selftype); + FScopeBarrier::ValidateCall(calledfunc, callingfunc, selftype); b -= 2; } #endif @@ -821,7 +821,7 @@ begin: if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); // [ZZ] validate readonly and between scope construction if (callingfunc) - FScopeBarrier_ValidateNew(cls, callingfunc); + FScopeBarrier::ValidateNew(cls, callingfunc); reg.a[a] = cls->CreateNew(); reg.atag[a] = ATAG_OBJECT; NEXTOP;