diff --git a/src/namedef.h b/src/namedef.h index af8028a95..39ea3c783 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -7,6 +7,7 @@ xx(Super) xx(Object) xx(Actor) xx(Class) +xx(Thinker) xx(Untranslated) @@ -343,6 +344,7 @@ xx(RandomPick) xx(FRandomPick) xx(SetRandomSeed) xx(BuiltinRandomSeed) +xx(BuiltinNew) xx(GetClass) xx(GetParentClass) xx(GetClassName) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index f8d68d586..72de1b6b3 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5138,9 +5138,54 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx) //========================================================================== // -// +// The CVAR is for finding places where thinkers are created. +// Those will require code changes in ZScript 4.0. // //========================================================================== +CVAR(Bool, vm_warnthinkercreation, false, 0) + +static DObject *BuiltinNew(PClass *cls, int outerside, int backwardscompatible) +{ + if (cls->ConstructNative == nullptr) + { + ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); + return nullptr; + } + if (cls->bAbstract) + { + ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); + return nullptr; + } + // Creating actors here must be outright prohibited, + if (cls->IsDescendantOf(NAME_Actor)) + { + ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); + return nullptr; + } + if (vm_warnthinkercreation && cls->IsDescendantOf(NAME_Thinker)) + { + // This must output a diagnostic warning + //ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); + //return nullptr; + } + // [ZZ] validate readonly and between scope construction + if (outerside) FScopeBarrier::ValidateNew(cls, outerside - 1); + auto object = cls->CreateNew(); + if (backwardscompatible && object->IsKindOf(NAME_Thinker)) + { + // Todo: Link thinker to current primary level. + } + return object; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinNew, BuiltinNew) +{ + PARAM_PROLOGUE; + PARAM_CLASS(cls, DObject); + PARAM_INT(outerside); + PARAM_INT(compatible); + ACTION_RETURN_OBJECT(BuiltinNew(cls, outerside, compatible)); +} ExpEmit FxNew::Emit(VMFunctionBuilder *build) { @@ -5148,18 +5193,27 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build) from.Free(build); ExpEmit to(build, REGT_POINTER); + // Call DecoRandom to generate a random number. + VMFunction *callfunc; + auto sym = FindBuiltinFunction(NAME_BuiltinNew); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + + int outerside = -1; if (!from.Konst) { int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags); if (outerside == FScopeBarrier::Side_Virtual) outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ScopeFlags); - 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; + emitters.AddParameter(from, false); + emitters.AddParameterIntConst(outerside); + emitters.AddParameterIntConst(1); // Todo: 1 only if version < 4.0.0 + emitters.AddReturn(REGT_POINTER); + return emitters.EmitCall(build); } //========================================================================== diff --git a/src/scripting/vm/jit_flow.cpp b/src/scripting/vm/jit_flow.cpp index 96b7bcec0..5db91818a 100644 --- a/src/scripting/vm/jit_flow.cpp +++ b/src/scripting/vm/jit_flow.cpp @@ -244,82 +244,6 @@ void JitCompiler::EmitRETI() } } -static DObject* CreateNew(PClass *cls, int c) -{ - if (!cls->ConstructNative) - { - ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); - } - else if (cls->bAbstract) - { - ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); - } - else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - } - - // [ZZ] validate readonly and between scope construction - if (c) FScopeBarrier::ValidateNew(cls, c - 1); - return cls->CreateNew(); -} - -void JitCompiler::EmitNEW() -{ - auto result = newResultIntPtr(); - auto call = CreateCall(CreateNew); - call->setRet(0, result); - call->setArg(0, regA[B]); - call->setArg(1, asmjit::Imm(C)); - - cc.mov(regA[A], result); -} - -static void ThrowNewK(PClass *cls, int c) -{ - if (!cls->ConstructNative) - { - ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); - } - else if (cls->bAbstract) - { - ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); - } - else // if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - } -} - -static DObject *CreateNewK(PClass *cls, int c) -{ - if (c) FScopeBarrier::ValidateNew(cls, c - 1); - return cls->CreateNew(); -} - -void JitCompiler::EmitNEW_K() -{ - PClass *cls = (PClass*)konsta[B].v; - auto regcls = newTempIntPtr(); - cc.mov(regcls, asmjit::imm_ptr(cls)); - - if (!cls->ConstructNative || cls->bAbstract || cls->IsDescendantOf(NAME_Actor)) - { - auto call = CreateCall(ThrowNewK); - call->setArg(0, regcls); - } - else - { - auto result = newResultIntPtr(); - auto call = CreateCall(CreateNewK); - call->setRet(0, result); - call->setArg(0, regcls); - call->setArg(1, asmjit::Imm(C)); - - cc.mov(regA[A], result); - } -} - void JitCompiler::EmitTHROW() { EmitThrowException(EVMAbortException(BC)); diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 97996376d..1aeea610a 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -757,34 +757,6 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) assert(0); NEXTOP; - OP(NEW_K): - OP(NEW): - { - b = B; - PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v); - if (cls->ConstructNative == nullptr) - { - ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars()); - return 0; - } - if (cls->bAbstract) - { - ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars()); - return 0; - } - // Creating actors here must be outright prohibited, - if (cls->IsDescendantOf(NAME_Actor)) - { - ThrowAbortException(X_OTHER, "Cannot create actors with 'new'"); - return 0; - } - // [ZZ] validate readonly and between scope construction - c = C; - if (c) FScopeBarrier::ValidateNew(cls, c - 1); - reg.a[a] = cls->CreateNew(); - NEXTOP; - } - #if 0 OP(TRY): assert(try_depth < MAX_TRY_DEPTH); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 0f181519e..82b3cabc4 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -108,8 +108,6 @@ xx(SCOPE, scope, RPI8, NOP, 0, 0) // Scope check at runtime. 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, 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 xx(THROW, throw, THROW, NOP, 0, 0) // A == 0: Throw exception object pB diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 704e736d2..f4d31b472 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -383,6 +383,7 @@ class Object native native bool bDestroyed; // These must be defined in some class, so that the compiler can find them. Object is just fine, as long as they are private to external code. + private native static Object BuiltinNew(Class cls, int outerclass, int compatibility); private native static int BuiltinRandom(voidptr rng, int min, int max); private native static double BuiltinFRandom(voidptr rng, double min, double max); private native static int BuiltinRandom2(voidptr rng, int mask);