From 8578a5a12e1517c342cabd1efb9ae38558e516ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 3 Feb 2017 22:56:03 +0100 Subject: [PATCH] - added a 'new' intrinsic to create new objects from inside scripts. This is not tested yet and likely to not working correctly yet. Will be fixed once I get far enough to use it later. --- src/namedef.h | 1 + src/scripting/codegeneration/codegen.cpp | 73 ++++++++++++++++++++++++ src/scripting/codegeneration/codegen.h | 21 +++++++ src/scripting/vm/vmdisasm.cpp | 1 + src/scripting/vm/vmexec.h | 8 +++ src/scripting/vm/vmops.h | 2 + 6 files changed, 106 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index ef7f1c58d..2bdb74ee6 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -346,6 +346,7 @@ xx(SinH) xx(TanH) xx(ATan2) xx(VectorAngle) +xx(New) xx(Alpha) xx(Angle) xx(Args) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8fd95c411..e6cd1989c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4918,6 +4918,70 @@ ExpEmit FxATan2::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// +// +//========================================================================== +FxNew::FxNew(FxExpression *v) + : FxExpression(EFX_New, v->ScriptPosition) +{ + val = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), v, false); + ValueType = NewPointer(RUNTIME_CLASS(DObject)); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxNew::~FxNew() +{ + SAFE_DELETE(val); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxNew::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(val, ctx); + + if (!val->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + { + ScriptPosition.Message(MSG_ERROR, "Class type expected"); + delete this; + return nullptr; + } + if (val->isConstant()) + { + auto cls = static_cast(static_cast(val)->GetValue().GetPointer()); + ValueType = NewPointer(cls); + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxNew::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == val->ValueType); + 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); + return to; +} + //========================================================================== // // The atan2 opcode only takes registers as parameters, so any constants @@ -7428,6 +7492,15 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_New: + if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) + { + func = new FxNew(ArgList[0]); + ArgList[0] = nullptr; + } + break; + + default: ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); break; diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 42d5b0ccf..69ad192f5 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -242,6 +242,7 @@ enum EFxType EFX_Conditional, EFX_Abs, EFX_ATan2, + EFX_New, EFX_MinMax, EFX_Random, EFX_RandomPick, @@ -1176,6 +1177,26 @@ public: private: ExpEmit ToReg(VMFunctionBuilder *build, FxExpression *val); }; + +//========================================================================== +// +// +// +//========================================================================== + +class FxNew : public FxExpression +{ + FxExpression *val; + +public: + + FxNew(FxExpression *v); + ~FxNew(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index d21e38d20..276533e2d 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -72,6 +72,7 @@ #define RFRF MODE_AF | MODE_BF | MODE_CUNUSED #define RSRS MODE_AS | MODE_BS | MODE_CUNUSED #define RPRP MODE_AP | MODE_BP | MODE_CUNUSED +#define RPKP MODE_AP | MODE_BKP | MODE_CUNUSED #define RXRXI8 MODE_AX | MODE_BX | MODE_CIMMZ #define RPRPRP MODE_AP | MODE_BP | MODE_CP #define RPRPKP MODE_AP | MODE_BP | MODE_CKP diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index d916658d7..fc6a53bee 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -759,6 +759,14 @@ begin: assert(0); NEXTOP; + OP(NEW_K): + OP(NEW): + { + PClass *cls = (PClass*)(op == OP_NEW ? reg.a[C] : konsta[C].v); + reg.a[B] = cls->CreateNew(); + NEXTOP; + } + OP(TRY): assert(try_depth < MAX_TRY_DEPTH); if (try_depth >= MAX_TRY_DEPTH) diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 0829ab2c6..86554940e 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -104,6 +104,8 @@ 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_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