From 403c5693a9482516731d68ce25959cc6e96d3788 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Mar 2017 21:25:30 +0100 Subject: [PATCH] - cleaned out a large part of unused methods from VMValue. - keep string registers which are being used as function parameters allocated until after the function call returns. This is for allowing to pass strings by reference which would avoid some costly constructor/destructor loops in the call instruction. --- src/scripting/backend/codegen.cpp | 43 ++++--- src/scripting/backend/codegen.h | 4 +- src/scripting/backend/vmbuilder.cpp | 1 + src/scripting/vm/vm.h | 175 ---------------------------- 4 files changed, 29 insertions(+), 194 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 7da591a0f..210bbdafd 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -503,7 +503,7 @@ static int EncodeRegType(ExpEmit reg) // //========================================================================== -static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) +static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos, TArray *tempstrings = nullptr) { ExpEmit where = operand->Emit(build); @@ -516,7 +516,14 @@ static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const else { build->Emit(OP_PARAM, 0, EncodeRegType(where), where.RegNum); - where.Free(build); + if (tempstrings != nullptr && where.RegType == REGT_STRING && !where.Fixed && !where.Konst) + { + tempstrings->Push(where); // keep temp strings until after the function call. + } + else + { + where.Free(build); + } return where.RegCount; } } @@ -6581,18 +6588,6 @@ FxClassDefaults::~FxClassDefaults() } -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxClassDefaults::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - //========================================================================== // // @@ -8572,7 +8567,6 @@ FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumen Self = self; Function = func; ArgList = std::move(args); - EmitTail = false; NoVirtual = novirtual; CallingFunction = nullptr; } @@ -8595,6 +8589,8 @@ FxVMFunctionCall::~FxVMFunctionCall() PPrototype *FxVMFunctionCall::ReturnProto() { + if (hasStringArgs) + return FxExpression::ReturnProto(); EmitTail = true; return Function->Variants[0].Proto; } @@ -8810,6 +8806,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } failed |= (x == nullptr); ArgList[i] = x; + if (!failed && x->ValueType == TypeString) + { + hasStringArgs = true; + } } int numargs = ArgList.Size() + implicit; if ((unsigned)numargs < argtypes.Size() && argtypes[numargs] != nullptr) @@ -8861,6 +8861,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { + TArray tempstrings; + assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); int count = 0; @@ -8873,6 +8875,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); + for (auto & exp : tempstrings) exp.Free(build); return reg; } } @@ -8939,7 +8942,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) // Emit code to pass explicit parameters for (unsigned i = 0; i < ArgList.Size(); ++i) { - count += EmitParameter(build, ArgList[i], ScriptPosition); + count += EmitParameter(build, ArgList[i], ScriptPosition, &tempstrings); } ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); @@ -8954,6 +8957,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) build->Emit(OP_TAIL_K, funcaddr, count, 0); ExpEmit call; call.Final = true; + for (auto & exp : tempstrings) exp.Free(build); return call; } else if (vmfunc->Proto->ReturnTypes.Size() > 0) @@ -8964,6 +8968,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) else { // Call, expecting no results build->Emit(OP_CALL_K, funcaddr, count, 0); + for (auto & exp : tempstrings) exp.Free(build); return ExpEmit(); } } @@ -8978,6 +8983,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) build->Emit(OP_TAIL, funcreg.RegNum, count, 0); ExpEmit call; call.Final = true; + for (auto & exp : tempstrings) exp.Free(build); return call; } else if (vmfunc->Proto->ReturnTypes.Size() > 0) @@ -8988,6 +8994,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) else { // Call, expecting no results build->Emit(OP_CALL, funcreg.RegNum, count, 0); + for (auto & exp : tempstrings) exp.Free(build); return ExpEmit(); } } @@ -8997,6 +9004,7 @@ handlereturns: // Regular call, will not write to ReturnRegs ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + for (auto & exp : tempstrings) exp.Free(build); return reg; } else @@ -9009,8 +9017,9 @@ handlereturns: build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); ReturnRegs.Push(reg); } - return ExpEmit(); } + for (auto & exp : tempstrings) exp.Free(build); + return ExpEmit(); } //========================================================================== diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index a75ea5b02..084ff52d7 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -407,7 +407,6 @@ class FxClassDefaults : public FxExpression public: FxClassDefaults(FxExpression *, const FScriptPosition &); ~FxClassDefaults(); - PPrototype *ReturnProto(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1704,8 +1703,9 @@ class FxVMFunctionCall : public FxExpression { friend class FxMultiAssign; - bool EmitTail; + bool EmitTail = false; bool NoVirtual; + bool hasStringArgs = false; FxExpression *Self; PFunction *Function; FArgumentList ArgList; diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index 308410922..899c4aee2 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -570,6 +570,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) assert(opb >= 0); assert(opc >= 0); + assert(opcode != OP_NOP); // The following were just asserts, meaning this would silently create broken code if there was an overflow // if this happened in a release build. Not good. diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index c099a4cb5..e545aebd3 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -481,181 +481,6 @@ struct VMValue atag = tag; Type = REGT_POINTER; } - VMValue &operator=(const VMValue &o) - { - if (o.Type == REGT_STRING) - { - if (Type == REGT_STRING) - { - s() = o.s(); - } - else - { - new(&s()) FString(o.s()); - Type = REGT_STRING; - } - } - else - { - Kill(); - biggest = o.biggest; - } - return *this; - } - VMValue &operator=(int v) - { - Kill(); - i = v; - Type = REGT_INT; - return *this; - } - VMValue &operator=(double v) - { - Kill(); - f = v; - Type = REGT_FLOAT; - return *this; - } - VMValue &operator=(const FString &v) - { - if (Type == REGT_STRING) - { - s() = v; - } - else - { - ::new(&s()) FString(v); - Type = REGT_STRING; - } - return *this; - } - VMValue &operator=(const char *v) - { - if (Type == REGT_STRING) - { - s() = v; - } - else - { - ::new(&s()) FString(v); - Type = REGT_STRING; - } - return *this; - } - VMValue &operator=(DObject *v) - { - Kill(); - a = v; - atag = ATAG_OBJECT; - Type = REGT_POINTER; - return *this; - } - void SetPointer(void *v, VM_ATAG atag=ATAG_GENERIC) - { - Kill(); - a = v; - this->atag = atag; - Type = REGT_POINTER; - } - void SetNil() - { - Kill(); - Type = REGT_NIL; - } - bool operator==(const VMValue &o) - { - return Test(o) == 0; - } - bool operator!=(const VMValue &o) - { - return Test(o) != 0; - } - bool operator< (const VMValue &o) - { - return Test(o) < 0; - } - bool operator<=(const VMValue &o) - { - return Test(o) <= 0; - } - bool operator> (const VMValue &o) - { - return Test(o) > 0; - } - bool operator>=(const VMValue &o) - { - return Test(o) >= 0; - } - int Test(const VMValue &o, int inexact=false) - { - double diff; - - if (Type == o.Type) - { - switch(Type) - { - case REGT_NIL: - return 0; - - case REGT_INT: - return i - o.i; - - case REGT_FLOAT: - diff = f - o.f; -do_double: if (inexact) - { - return diff < -VM_EPSILON ? -1 : diff > VM_EPSILON ? 1 : 0; - } - return diff < 0 ? -1 : diff > 0 ? 1 : 0; - - case REGT_STRING: - return inexact ? s().CompareNoCase(o.s()) : s().Compare(o.s()); - - case REGT_POINTER: - return int((const VM_UBYTE *)a - (const VM_UBYTE *)o.a); - } - assert(0); // Should not get here - return 2; - } - if (Type == REGT_FLOAT && o.Type == REGT_INT) - { - diff = f - o.i; - goto do_double; - } - if (Type == REGT_INT && o.Type == REGT_FLOAT) - { - diff = i - o.f; - goto do_double; - } - // Bad comparison - return 2; - } - FString ToString() - { - if (Type == REGT_STRING) - { - return s(); - } - else if (Type == REGT_NIL) - { - return "nil"; - } - FString t; - if (Type == REGT_INT) - { - t.Format ("%d", i); - } - else if (Type == REGT_FLOAT) - { - t.Format ("%.14g", f); - } - else if (Type == REGT_POINTER) - { - // FIXME - t.Format ("Object: %p", a); - } - return t; - } int ToInt() { if (Type == REGT_INT)