- simplify the runtime checks for OP_NEW.

They are not needed for OP_NEW_K which can evaluate the class relations at compile time and for OP_NEW the calling function can also be checked at compile time, passing only the scope value itself.
This commit is contained in:
Christoph Oelckers 2017-03-07 19:57:55 +01:00
parent 7a0c466b24
commit 0c686c593b
5 changed files with 17 additions and 10 deletions

View File

@ -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;
}

View File

@ -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));

View File

@ -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);
};

View File

@ -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;

View File

@ -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