mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- made OP_NEW a builtin function instead of an opcode.
The code was present 3 times due to the JIt, and this is not something that benefits from being a real opcode, even in the interpreted case.
This commit is contained in:
parent
cc73449d29
commit
4126f8ce72
6 changed files with 64 additions and 113 deletions
|
@ -7,6 +7,7 @@ xx(Super)
|
||||||
xx(Object)
|
xx(Object)
|
||||||
xx(Actor)
|
xx(Actor)
|
||||||
xx(Class)
|
xx(Class)
|
||||||
|
xx(Thinker)
|
||||||
|
|
||||||
xx(Untranslated)
|
xx(Untranslated)
|
||||||
|
|
||||||
|
@ -343,6 +344,7 @@ xx(RandomPick)
|
||||||
xx(FRandomPick)
|
xx(FRandomPick)
|
||||||
xx(SetRandomSeed)
|
xx(SetRandomSeed)
|
||||||
xx(BuiltinRandomSeed)
|
xx(BuiltinRandomSeed)
|
||||||
|
xx(BuiltinNew)
|
||||||
xx(GetClass)
|
xx(GetClass)
|
||||||
xx(GetParentClass)
|
xx(GetParentClass)
|
||||||
xx(GetClassName)
|
xx(GetClassName)
|
||||||
|
|
|
@ -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)
|
ExpEmit FxNew::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
|
@ -5148,18 +5193,27 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build)
|
||||||
from.Free(build);
|
from.Free(build);
|
||||||
ExpEmit to(build, REGT_POINTER);
|
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)
|
if (!from.Konst)
|
||||||
{
|
{
|
||||||
int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags);
|
int outerside = FScopeBarrier::SideFromFlags(CallingFunction->Variants[0].Flags);
|
||||||
if (outerside == FScopeBarrier::Side_Virtual)
|
if (outerside == FScopeBarrier::Side_Virtual)
|
||||||
outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ScopeFlags);
|
outerside = FScopeBarrier::SideFromObjectFlags(CallingFunction->OwningClass->ScopeFlags);
|
||||||
build->Emit(OP_NEW, to.RegNum, from.RegNum, outerside+1); // +1 to ensure it's not 0
|
|
||||||
}
|
}
|
||||||
else
|
emitters.AddParameter(from, false);
|
||||||
{
|
emitters.AddParameterIntConst(outerside);
|
||||||
build->Emit(OP_NEW_K, to.RegNum, from.RegNum);
|
emitters.AddParameterIntConst(1); // Todo: 1 only if version < 4.0.0
|
||||||
}
|
emitters.AddReturn(REGT_POINTER);
|
||||||
return to;
|
return emitters.EmitCall(build);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -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<DObject*, PClass*, int>(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<void, PClass*, int>(ThrowNewK);
|
|
||||||
call->setArg(0, regcls);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto result = newResultIntPtr();
|
|
||||||
auto call = CreateCall<DObject*, PClass*, int>(CreateNewK);
|
|
||||||
call->setRet(0, result);
|
|
||||||
call->setArg(0, regcls);
|
|
||||||
call->setArg(1, asmjit::Imm(C));
|
|
||||||
|
|
||||||
cc.mov(regA[A], result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JitCompiler::EmitTHROW()
|
void JitCompiler::EmitTHROW()
|
||||||
{
|
{
|
||||||
EmitThrowException(EVMAbortException(BC));
|
EmitThrowException(EVMAbortException(BC));
|
||||||
|
|
|
@ -757,34 +757,6 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
|
||||||
assert(0);
|
assert(0);
|
||||||
NEXTOP;
|
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
|
#if 0
|
||||||
OP(TRY):
|
OP(TRY):
|
||||||
assert(try_depth < MAX_TRY_DEPTH);
|
assert(try_depth < MAX_TRY_DEPTH);
|
||||||
|
|
|
@ -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(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(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(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(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(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
|
xx(THROW, throw, THROW, NOP, 0, 0) // A == 0: Throw exception object pB
|
||||||
|
|
|
@ -383,6 +383,7 @@ class Object native
|
||||||
native bool bDestroyed;
|
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.
|
// 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<Object> cls, int outerclass, int compatibility);
|
||||||
private native static int BuiltinRandom(voidptr rng, int min, int max);
|
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 double BuiltinFRandom(voidptr rng, double min, double max);
|
||||||
private native static int BuiltinRandom2(voidptr rng, int mask);
|
private native static int BuiltinRandom2(voidptr rng, int mask);
|
||||||
|
|
Loading…
Reference in a new issue