diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 12a0c44e08..addc07f4b7 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5105,7 +5105,18 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) ExpEmit from = val->Emit(build); from.Free(build); ExpEmit to(build, REGT_POINTER); - build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum, build->GetConstantAddress(CallingFunction, ATAG_OBJECT)); + + if (!from.Konst) + { + int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); + if (outerside == FScopeBarrier::Side_Virtual) + outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ObjectFlags); + build->Emit(OP_NEW, to.RegNum, from.RegNum, outerside+1); // +1 to ensure it's not 0 + } + else + { + build->Emit(OP_NEW_K, to.RegNum, from.RegNum); + } return to; } diff --git a/src/scripting/backend/scopebarrier.cpp b/src/scripting/backend/scopebarrier.cpp index ad104f3178..3ba207fba1 100644 --- a/src/scripting/backend/scopebarrier.cpp +++ b/src/scripting/backend/scopebarrier.cpp @@ -173,11 +173,8 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name) } // these are for vmexec.h -void FScopeBarrier::ValidateNew(PClass* cls, PFunction* callingfunc) +void FScopeBarrier::ValidateNew(PClass* cls, int outerside) { - 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)); diff --git a/src/scripting/backend/scopebarrier.h b/src/scripting/backend/scopebarrier.h index db8a5044a4..af3951a8d6 100644 --- a/src/scripting/backend/scopebarrier.h +++ b/src/scripting/backend/scopebarrier.h @@ -53,7 +53,7 @@ struct FScopeBarrier void AddFlags(int flags1, int flags2, const char* name); // this is called from vmexec.h - static void ValidateNew(PClass* cls, PFunction* callingfunc); + static void ValidateNew(PClass* cls, int scope); static void ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype); }; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 0281be3df1..a822aef530 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -817,11 +817,10 @@ begin: { b = B; PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v); - PFunction *callingfunc = (PFunction*)konsta[C].o; // [ZZ] due to how this is set, it's always const 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); + c = C; + if (c) FScopeBarrier::ValidateNew(cls, c - 1); reg.a[a] = cls->CreateNew(); reg.atag[a] = ATAG_OBJECT; NEXTOP; diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 3d503932aa..b9cba87d29 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -111,7 +111,7 @@ xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER), xx(RESULT, result, __BCP, NOP, 0, 0), // Result should go in register encoded in BC (in caller, after CALL) xx(RET, ret, I8BCP, NOP, 0, 0), // Copy value from register encoded in BC to return value A, possibly returning xx(RETI, reti, I8I16, NOP, 0, 0), // Copy immediate from BC to return value A, possibly returning -xx(NEW, new, RPRP, NOP, 0, 0), +xx(NEW, new, RPRPI8, NOP, 0, 0), xx(NEW_K, new, RPKP, NOP, 0, 0), xx(TRY, try, I24, NOP, 0, 0), // When an exception is thrown, start searching for a handler at pc + ABC xx(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack