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)