From a9ec819557ab855526ddf490af1f8052b2109a85 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 18 Nov 2018 19:31:13 +0100 Subject: [PATCH] - moved the type infomation entirely out of VMValue. For the varargs functions that used the Type field to validate their parameters, now a hidden additional argument is passed which contains a byte array with the type info for the current call's arguments. Since this is static per call location it can be better prepared once when the code is being compiled instead of being put in a runtime created array for each invocation. Everything else uses the per-function instance of the same data. The only thing that still needed the type field with a VMValue is the defaults array, so this uses a different struct type now to store its data. --- src/c_console.cpp | 5 +- src/d_dehacked.cpp | 3 +- src/info.cpp | 8 +- src/p_actionfunctions.cpp | 8 +- src/scripting/backend/codegen.cpp | 82 ++++++------- src/scripting/backend/codegen.h | 2 +- src/scripting/backend/vmbuilder.cpp | 27 ++++ src/scripting/backend/vmbuilder.h | 16 ++- src/scripting/thingdef_data.cpp | 32 +++-- src/scripting/vm/jit_call.cpp | 32 ----- src/scripting/vm/vm.h | 169 +++++++++++++++++++------- src/scripting/vm/vmexec.cpp | 1 - src/scripting/vm/vmexec.h | 2 +- src/scripting/vm/vmframe.cpp | 6 +- src/scripting/zscript/zcc_compile.cpp | 4 +- src/v_draw.cpp | 23 +++- src/v_text.cpp | 8 +- src/v_video.h | 1 + 18 files changed, 265 insertions(+), 164 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 115d2bc43..9a38ae1cf 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -62,7 +62,6 @@ #include "g_levellocals.h" #include "vm.h" -FString FStringFormat(VM_ARGS); // extern from thingdef_data.cpp #include "gi.h" @@ -1294,7 +1293,9 @@ DEFINE_ACTION_FUNCTION(_Console, HideConsole) DEFINE_ACTION_FUNCTION(_Console, Printf) { PARAM_PROLOGUE; - FString s = FStringFormat(param, numparam, ret, numret); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + + FString s = FStringFormat(VM_ARGS_NAMES); Printf("%s\n", s.GetChars()); return 0; } diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 89ac12401..2adc83c92 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -777,14 +777,13 @@ void SetDehParams(FState *state, int codepointer) // self, stateowner, state (all are pointers) buildit.Registers[REGT_POINTER].Get(numargs); // Emit code to pass the standard action function parameters. - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(sym->Variants[0].Implementation); for (int i = 0; i < numargs; i++) { emitters.AddParameterPointer(i, false); } // Emit code for action parameters. MBFCodePointerFactories[codepointer](emitters, value1, value2); - emitters.AddTarget(sym->Variants[0].Implementation); emitters.EmitCall(&buildit); buildit.Emit(OP_RET, RET_FINAL, REGT_NIL, 0); // Attach it to the state. diff --git a/src/info.cpp b/src/info.cpp index 385dc5bd4..cfa6b067b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -181,7 +181,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, if (ActionFunc->DefaultArgs.Size() > 0) { - auto index = actionParams.Append(ActionFunc->DefaultArgs); + auto defs = ActionFunc->DefaultArgs; + auto index = actionParams.Reserve(defs.Size()); + for (unsigned i = 0; i < defs.Size(); i++) + { + actionParams[i + index] = defs[i]; + } + if (ActionFunc->ImplicitArgs >= 1) { actionParams[index] = self; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 4c22eae16..3789fe7cd 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -175,7 +175,13 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) if (state->ActionFunc->DefaultArgs.Size() > 0) { - auto index = actionParams.Append(state->ActionFunc->DefaultArgs); + auto defs = state->ActionFunc->DefaultArgs; + auto index = actionParams.Reserve(defs.Size()); + for (unsigned i = 0; i < defs.Size(); i++) + { + actionParams[i + index] = defs[i]; + } + if (state->ActionFunc->ImplicitArgs >= 1) { actionParams[index] = actor; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index aba8102c1..b15cccea4 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5471,7 +5471,7 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinRandom(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinRandom(VM_ARGS) { PARAM_PROLOGUE; PARAM_POINTER(rng, FRandom); @@ -5496,12 +5496,11 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(callfunc); emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); emitters.AddParameter(build, max); - emitters.AddTarget(callfunc); emitters.AddReturn(REGT_INT); return emitters.EmitCall(build); } @@ -5604,11 +5603,10 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(callfunc); emitters.AddParameterPointerConst(rng); emitters.AddParameterIntConst(0); emitters.AddParameterIntConst(choices.Size() - 1); - emitters.AddTarget(callfunc); emitters.AddReturn(REGT_INT); auto resultreg = emitters.EmitCall(build); @@ -5696,7 +5694,7 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri // //========================================================================== -int BuiltinFRandom(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinFRandom(VM_ARGS) { PARAM_PROLOGUE; PARAM_POINTER(rng, FRandom); @@ -5725,11 +5723,10 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(min && max); callfunc = ((PSymbolVMFunction *)sym)->Function; - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(callfunc); emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, min); emitters.AddParameter(build, max); - emitters.AddTarget(callfunc); emitters.AddReturn(REGT_FLOAT); return emitters.EmitCall(build); } @@ -5779,7 +5776,7 @@ FxExpression *FxRandom2::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinRandom2(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinRandom2(VM_ARGS) { PARAM_PROLOGUE; PARAM_POINTER(rng, FRandom); @@ -5804,11 +5801,10 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(callfunc); emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, mask); - emitters.AddTarget(callfunc); emitters.AddReturn(REGT_INT); return emitters.EmitCall(build); } @@ -5857,7 +5853,7 @@ FxExpression *FxRandomSeed::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinRandomSeed(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinRandomSeed(VM_ARGS) { PARAM_PROLOGUE; PARAM_POINTER(rng, FRandom) @@ -5877,11 +5873,9 @@ ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - FunctionCallEmitter emitters; - + FunctionCallEmitter emitters(callfunc); emitters.AddParameterPointerConst(rng); emitters.AddParameter(build, seed); - emitters.AddTarget(callfunc); return emitters.EmitCall(build); } @@ -6320,7 +6314,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); auto sn = static_cast(sym); - VMValue vmv; + TypedVMValue vmv; if (sn->ValueType->isIntCompatible()) vmv = sn->Value; else vmv = sn->Float; auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition); @@ -8526,7 +8520,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) // //========================================================================== -int BuiltinCallLineSpecial(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinCallLineSpecial(VM_ARGS) { PARAM_PROLOGUE; PARAM_INT(special); @@ -8544,7 +8538,15 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) { unsigned i = 0; - FunctionCallEmitter emitters; + // Call the BuiltinCallLineSpecial function to perform the desired special. + static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT }; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial, reginfo); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + VMFunction *callfunc = ((PSymbolVMFunction *)sym)->Function; + + FunctionCallEmitter emitters(callfunc); emitters.AddParameterIntConst(abs(Special)); // pass special number emitters.AddParameter(build, Self); @@ -8571,18 +8573,9 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) } } } - // Call the BuiltinCallLineSpecial function to perform the desired special. - VMFunction *callfunc; - static uint8_t reginfo[] = { REGT_INT, REGT_POINTER, REGT_INT, REGT_INT, REGT_INT, REGT_INT, REGT_INT }; - PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial, reginfo); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - callfunc = ((PSymbolVMFunction *)sym)->Function; ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); - emitters.AddTarget(callfunc); emitters.AddReturn(REGT_INT); return emitters.EmitCall(build); } @@ -8989,7 +8982,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual); count = 0; - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(vmfunc); // Emit code to pass implied parameters ExpEmit selfemit; if (Function->Variants[0].Flags & VARF_Method) @@ -9063,7 +9056,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); - emitters.AddTarget(vmfunc, staticcall? -1 : selfemit.RegNum); + if (!staticcall) emitters.SetVirtualReg(selfemit.RegNum); int resultcount = vmfunc->Proto->ReturnTypes.Size() == 0 ? 0 : MAX(AssignCount, 1); assert((unsigned)resultcount <= vmfunc->Proto->ReturnTypes.Size()); @@ -10582,9 +10575,8 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) assert(pstr->mDestructor != nullptr); ExpEmit reg(build, REGT_POINTER); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset)); - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(pstr->mDestructor); emitters.AddParameter(reg, false); - emitters.AddTarget(pstr->mDestructor); emitters.EmitCall(build); } @@ -10752,7 +10744,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinNameToClass(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinNameToClass(VM_ARGS) { PARAM_PROLOGUE; PARAM_NAME(clsname); @@ -10777,9 +10769,6 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) { return ExpEmit(build->GetConstantAddress(nullptr), REGT_POINTER, true); } - FunctionCallEmitter emitters; - emitters.AddParameter(build, basex); - emitters.AddParameterPointerConst(const_cast(desttype)); // Call the BuiltinNameToClass function to convert from 'name' to class. VMFunction *callfunc; @@ -10790,7 +10779,9 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - emitters.AddTarget(callfunc); + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, basex); + emitters.AddParameterPointerConst(const_cast(desttype)); emitters.AddReturn(REGT_POINTER); return emitters.EmitCall(build); } @@ -10875,7 +10866,7 @@ FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) // //========================================================================== -int BuiltinClassCast(VMValue *param, int numparam, VMReturn *ret, int numret) +int BuiltinClassCast(VM_ARGS) { PARAM_PROLOGUE; PARAM_CLASS(from, DObject); @@ -10887,11 +10878,6 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) { ExpEmit clsname = basex->Emit(build); - FunctionCallEmitter emitters; - - emitters.AddParameter(clsname, false); - emitters.AddParameterPointerConst(desttype); - VMFunction *callfunc; static uint8_t reginfo[] = { REGT_POINTER, REGT_POINTER }; PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast, reginfo); @@ -10899,7 +10885,11 @@ ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - emitters.AddTarget(callfunc); + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(clsname, false); + emitters.AddParameterPointerConst(desttype); + emitters.AddReturn(REGT_POINTER); return emitters.EmitCall(build); } @@ -11274,9 +11264,8 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { ExpEmit reg(build, REGT_POINTER); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(pstr->mConstructor); emitters.AddParameter(reg, false); - emitters.AddTarget(pstr->mConstructor); emitters.EmitCall(build); } if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this); @@ -11301,9 +11290,8 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { ExpEmit reg(build, REGT_POINTER); build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); - FunctionCallEmitter emitters; + FunctionCallEmitter emitters(pstr->mDestructor); emitters.AddParameter(reg, false); - emitters.AddTarget(pstr->mDestructor); emitters.EmitCall(build); } build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this)); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index ba0bb4d41..3876f9626 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -514,7 +514,7 @@ public: isresolved = true; } - FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + FxConstant(PType *type, TypedVMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { isresolved = true; switch (vmval.Type) diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index f11feab86..d1566730d 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -941,6 +941,8 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o operand->ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value"); } numparams += where.RegCount; + if (target->VarFlags & VARF_VarArg) + for (unsigned i = 0; i < where.RegCount; i++) reginfo.Push(where.RegType & REGT_TYPE); emitters.push_back([=](VMFunctionBuilder *build) -> int { @@ -962,6 +964,11 @@ void FunctionCallEmitter::AddParameter(VMFunctionBuilder *build, FxExpression *o void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference) { numparams += emit.RegCount; + if (target->VarFlags & VARF_VarArg) + { + if (reference) reginfo.Push(REGT_POINTER); + else for (unsigned i = 0; i < emit.RegCount; i++) reginfo.Push(emit.RegType & REGT_TYPE); + } emitters.push_back([=](VMFunctionBuilder *build) ->int { build->Emit(OP_PARAM, emit.RegType + (reference * REGT_ADDROF), emit.RegNum); @@ -974,6 +981,8 @@ void FunctionCallEmitter::AddParameter(ExpEmit &emit, bool reference) void FunctionCallEmitter::AddParameterPointerConst(void *konst) { numparams++; + if (target->VarFlags & VARF_VarArg) + reginfo.Push(REGT_POINTER); emitters.push_back([=](VMFunctionBuilder *build) ->int { build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(konst)); @@ -984,6 +993,8 @@ void FunctionCallEmitter::AddParameterPointerConst(void *konst) void FunctionCallEmitter::AddParameterPointer(int index, bool konst) { numparams++; + if (target->VarFlags & VARF_VarArg) + reginfo.Push(REGT_POINTER); emitters.push_back([=](VMFunctionBuilder *build) ->int { build->Emit(OP_PARAM, konst ? REGT_POINTER | REGT_KONST : REGT_POINTER, index); @@ -994,6 +1005,8 @@ void FunctionCallEmitter::AddParameterPointer(int index, bool konst) void FunctionCallEmitter::AddParameterFloatConst(double konst) { numparams++; + if (target->VarFlags & VARF_VarArg) + reginfo.Push(REGT_FLOAT); emitters.push_back([=](VMFunctionBuilder *build) ->int { build->Emit(OP_PARAM, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(konst)); @@ -1004,6 +1017,8 @@ void FunctionCallEmitter::AddParameterFloatConst(double konst) void FunctionCallEmitter::AddParameterIntConst(int konst) { numparams++; + if (target->VarFlags & VARF_VarArg) + reginfo.Push(REGT_INT); emitters.push_back([=](VMFunctionBuilder *build) ->int { // Immediates for PARAMI must fit in 24 bits. @@ -1022,6 +1037,8 @@ void FunctionCallEmitter::AddParameterIntConst(int konst) void FunctionCallEmitter::AddParameterStringConst(const FString &konst) { numparams++; + if (target->VarFlags & VARF_VarArg) + reginfo.Push(REGT_STRING); emitters.push_back([=](VMFunctionBuilder *build) ->int { build->Emit(OP_PARAM, REGT_STRING | REGT_KONST, build->GetConstantString(konst)); @@ -1037,6 +1054,16 @@ ExpEmit FunctionCallEmitter::EmitCall(VMFunctionBuilder *build, TArray paramcount += func(build); } assert(paramcount == numparams); + if (target->VarFlags & VARF_VarArg) + { + // Pass a hidden type information parameter to vararg functions. + // It would really be nicer to actually pass real types but that'd require a far more complex interface on the compiler side than what we have. + uint8_t *regbuffer = (uint8_t*)ClassDataAllocator.Alloc(reginfo.Size()); // Allocate in the arena so that the pointer does not need to be maintained. + memcpy(regbuffer, reginfo.Data(), reginfo.Size()); + build->Emit(OP_PARAM, REGT_POINTER | REGT_KONST, build->GetConstantAddress(regbuffer)); + paramcount++; + } + if (virtualselfreg == -1) { diff --git a/src/scripting/backend/vmbuilder.h b/src/scripting/backend/vmbuilder.h index 7531e4eff..28b6798d5 100644 --- a/src/scripting/backend/vmbuilder.h +++ b/src/scripting/backend/vmbuilder.h @@ -169,11 +169,22 @@ class FunctionCallEmitter // std::function and TArray are not compatible so this has to use std::vector instead. std::vector> emitters; TArray> returns; + TArray reginfo; unsigned numparams = 0; // This counts the number of pushed elements, which can differ from the number of emitters with vectors. VMFunction *target = nullptr; int virtualselfreg = -1; public: + FunctionCallEmitter(VMFunction *func) + { + target = func; + } + + void SetVirtualReg(int virtreg) + { + virtualselfreg = virtreg; + } + void AddParameter(VMFunctionBuilder *build, FxExpression *operand); void AddParameter(ExpEmit &emit, bool reference); void AddParameterPointerConst(void *konst); @@ -186,11 +197,6 @@ public: { returns.Push({ regtype, regcount }); } - void AddTarget(VMFunction *func, int virtreg = -1) - { - target = func; - virtualselfreg = virtreg; - } unsigned Count() const { return numparams; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 531af0701..019c10b3a 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1020,10 +1020,16 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Replace) return 0; } -FString FStringFormat(VM_ARGS) +FString FStringFormat(VM_ARGS, int offset) { - assert(param[0].Type == REGT_STRING); - FString fmtstring = param[0].s().GetChars(); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + assert(va_reginfo[offset] == REGT_STRING); + + FString fmtstring = param[offset].s().GetChars(); + + param += offset; + numparam -= offset; + va_reginfo += offset; // note: we don't need a real printf format parser. // enough to simply find the subtitution tokens and feed them to the real printf after checking types. @@ -1074,7 +1080,7 @@ FString FStringFormat(VM_ARGS) in_fmt = false; // fail if something was found, but it's not a string if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (param[argnum].Type != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum] != REGT_STRING) ThrowAbortException(X_FORMAT_ERROR, "Expected a string for format %s.", fmt_current.GetChars()); // append output.AppendFormat(fmt_current.GetChars(), param[argnum].s().GetChars()); if (!haveargnums) argnum = ++argauto; @@ -1090,7 +1096,7 @@ FString FStringFormat(VM_ARGS) in_fmt = false; // fail if something was found, but it's not a string if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (param[argnum].Type != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum] != REGT_POINTER) ThrowAbortException(X_FORMAT_ERROR, "Expected a pointer for format %s.", fmt_current.GetChars()); // append output.AppendFormat(fmt_current.GetChars(), param[argnum].a); if (!haveargnums) argnum = ++argauto; @@ -1112,10 +1118,10 @@ FString FStringFormat(VM_ARGS) in_fmt = false; // fail if something was found, but it's not an int if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (param[argnum].Type != REGT_INT && - param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); // append - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt()); + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToInt(va_reginfo[argnum])); if (!haveargnums) argnum = ++argauto; else argnum = -1; break; @@ -1136,10 +1142,10 @@ FString FStringFormat(VM_ARGS) in_fmt = false; // fail if something was found, but it's not a float if (argnum >= numparam) ThrowAbortException(X_FORMAT_ERROR, "Not enough arguments for format."); - if (param[argnum].Type != REGT_INT && - param[argnum].Type != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); + if (va_reginfo[argnum] != REGT_INT && + va_reginfo[argnum] != REGT_FLOAT) ThrowAbortException(X_FORMAT_ERROR, "Expected a numeric value for format %s.", fmt_current.GetChars()); // append - output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble()); + output.AppendFormat(fmt_current.GetChars(), param[argnum].ToDouble(va_reginfo[argnum])); if (!haveargnums) argnum = ++argauto; else argnum = -1; break; @@ -1181,7 +1187,7 @@ FString FStringFormat(VM_ARGS) DEFINE_ACTION_FUNCTION(FStringStruct, Format) { PARAM_PROLOGUE; - FString s = FStringFormat(param, numparam, ret, numret); + FString s = FStringFormat(VM_ARGS_NAMES); ACTION_RETURN_STRING(s); } @@ -1189,7 +1195,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat) { PARAM_SELF_STRUCT_PROLOGUE(FString); // first parameter is the self pointer - FString s = FStringFormat(param+1, numparam-1, ret, numret); + FString s = FStringFormat(VM_ARGS_NAMES, 1); (*self) += s; return 0; } diff --git a/src/scripting/vm/jit_call.cpp b/src/scripting/vm/jit_call.cpp index 92f596693..444bc04b8 100644 --- a/src/scripting/vm/jit_call.cpp +++ b/src/scripting/vm/jit_call.cpp @@ -129,8 +129,6 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget) { int abcs = ParamOpcodes[i]->i24; cc.mov(asmjit::x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), abcs); - if (!simpleFrameTarget) - cc.mov(asmjit::x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT); continue; } @@ -140,71 +138,47 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget) { case REGT_NIL: cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), (int64_t)0); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_NIL); break; case REGT_INT: cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), regD[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT); break; case REGT_INT | REGT_ADDROF: cc.lea(stackPtr, x86::ptr(vmframe, offsetD + (int)(bc * sizeof(int32_t)))); cc.mov(x86::dword_ptr(stackPtr), regD[bc]); cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_INT | REGT_KONST: cc.mov(x86::dword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, i)), konstd[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_INT); break; case REGT_STRING: cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), regS[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_STRING); break; case REGT_STRING | REGT_ADDROF: cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regS[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_STRING | REGT_KONST: cc.mov(tmp, asmjit::imm_ptr(&konsts[bc])); cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, sp)), tmp); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_STRING); break; case REGT_POINTER: cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), regA[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_POINTER | REGT_ADDROF: cc.lea(stackPtr, x86::ptr(vmframe, offsetA + (int)(bc * sizeof(void*)))); cc.mov(x86::ptr(stackPtr), regA[bc]); cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_POINTER | REGT_KONST: cc.mov(tmp, asmjit::imm_ptr(konsta[bc].v)); cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), tmp); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_FLOAT: cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT); break; case REGT_FLOAT | REGT_MULTIREG2: for (int j = 0; j < 2; j++) { cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT); } numparams++; break; @@ -212,8 +186,6 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget) for (int j = 0; j < 3; j++) { cc.movsd(x86::qword_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, f)), regF[bc + j]); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + (slot + j) * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT); } numparams += 2; break; @@ -226,15 +198,11 @@ int JitCompiler::StoreCallParams(bool simpleFrameTarget) cc.movsd(x86::qword_ptr(stackPtr, j * sizeof(double)), regF[bc + j]); } cc.mov(x86::ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, a)), stackPtr); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_POINTER); break; case REGT_FLOAT | REGT_KONST: cc.mov(tmp, asmjit::imm_ptr(konstf + bc)); cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp)); cc.movsd(x86::qword_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, f)), tmp2); - if (!simpleFrameTarget) - cc.mov(x86::byte_ptr(vmframe, offsetParams + slot * sizeof(VMValue) + myoffsetof(VMValue, Type)), (int)REGT_FLOAT); break; default: diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index f1266bd51..3c856f103 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -196,8 +196,7 @@ struct VMReturn struct VMRegisters; - -struct VMValue +struct TypedVMValue { union { @@ -211,11 +210,90 @@ struct VMValue const FString &s() const { return *sp; } - VMValue() + TypedVMValue() { a = NULL; Type = REGT_NIL; } + TypedVMValue(const TypedVMValue &o) + { + biggest = o.biggest; + } + TypedVMValue(int v) + { + i = v; + Type = REGT_INT; + } + TypedVMValue(double v) + { + f = v; + Type = REGT_FLOAT; + } + + TypedVMValue(const FString *s) + { + sp = s; + Type = REGT_STRING; + } + TypedVMValue(DObject *v) + { + a = v; + Type = REGT_POINTER; + } + TypedVMValue(void *v) + { + a = v; + Type = REGT_POINTER; + } + TypedVMValue &operator=(const TypedVMValue &o) + { + biggest = o.biggest; + return *this; + } + TypedVMValue &operator=(int v) + { + i = v; + Type = REGT_INT; + return *this; + } + TypedVMValue &operator=(double v) + { + f = v; + Type = REGT_FLOAT; + return *this; + } + TypedVMValue &operator=(const FString *v) + { + sp = v; + Type = REGT_STRING; + return *this; + } + TypedVMValue &operator=(DObject *v) + { + a = v; + Type = REGT_POINTER; + return *this; + } +}; + + +struct VMValue +{ + union + { + int i; + void *a; + double f; + struct { int foo[2]; } biggest; + const FString *sp; + }; + + const FString &s() const { return *sp; } + + VMValue() + { + a = NULL; + } VMValue(const VMValue &o) { biggest = o.biggest; @@ -223,12 +301,10 @@ struct VMValue VMValue(int v) { i = v; - Type = REGT_INT; } VMValue(double v) { f = v; - Type = REGT_FLOAT; } VMValue(const char *s) = delete; VMValue(const FString &s) = delete; @@ -236,39 +312,38 @@ struct VMValue VMValue(const FString *s) { sp = s; - Type = REGT_STRING; } VMValue(DObject *v) { a = v; - Type = REGT_POINTER; } VMValue(void *v) { a = v; - Type = REGT_POINTER; } VMValue &operator=(const VMValue &o) { biggest = o.biggest; return *this; } + VMValue &operator=(const TypedVMValue &o) + { + memcpy(&biggest, &o.biggest, sizeof(biggest)); + return *this; + } VMValue &operator=(int v) { i = v; - Type = REGT_INT; return *this; } VMValue &operator=(double v) { f = v; - Type = REGT_FLOAT; return *this; } VMValue &operator=(const FString *v) { sp = v; - Type = REGT_STRING; return *this; } VMValue &operator=(const FString &v) = delete; @@ -276,10 +351,9 @@ struct VMValue VMValue &operator=(DObject *v) { a = v; - Type = REGT_POINTER; return *this; } - int ToInt() + int ToInt(int Type) { if (Type == REGT_INT) { @@ -296,7 +370,7 @@ struct VMValue // FIXME return 0; } - double ToDouble() + double ToDouble(int Type) { if (Type == REGT_FLOAT) { @@ -324,7 +398,7 @@ public: unsigned VirtualIndex = ~0u; FName Name; const uint8_t *RegTypes = nullptr; - TArray DefaultArgs; + TArray DefaultArgs; FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. class PPrototype *Proto; @@ -365,10 +439,22 @@ protected: void CreateRegUse(); }; +// Use this in the prototype for a native function. + +#ifdef NDEBUG +#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret +#define VM_ARGS_NAMES param, numparam, ret, numret +#define VM_INVOKE(param, numparam, ret, numret, reginfo) (param), (numparam), (ret), (numret) +#else +#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret, const uint8_t *reginfo +#define VM_ARGS_NAMES param, numparam, ret, numret, reginfo +#define VM_INVOKE(param, numparam, ret, numret, reginfo) (param), (numparam), (ret), (numret), (reginfo) +#endif + class VMNativeFunction : public VMFunction { public: - typedef int (*NativeCallType)(VMValue *param, int numparam, VMReturn *ret, int numret); + typedef int (*NativeCallType)(VM_ARGS); // 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype. VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; ScriptCall = &VMNativeFunction::NativeScriptCall; } @@ -390,10 +476,6 @@ inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMRetu return VMCall(func, params, numparams, results, numresults); } -// Use this in the prototype for a native function. -#define VM_ARGS VMValue *param, int numparam, VMReturn *ret, int numret -#define VM_ARGS_NAMES param, numparam, ret, numret - // Use these to collect the parameters in a native function. // variable name at position

void NullParam(const char *varname); @@ -404,31 +486,28 @@ bool AssertObject(void * ob); #define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr) -#define ASSERTINT(p) assert((p).Type == REGT_INT) -#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) -#define ASSERTSTRING(p) assert((p).Type == REGT_STRING) -#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && AssertObject(p.a)) -#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER) +// This cannot assert because there is no info for varargs +#define PARAM_VA_POINTER(x) const uint8_t *x = (const uint8_t *)param[numparam-1].a; // For required parameters. -#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; -#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); unsigned x = param[p].i; -#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i; -#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i); -#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; -#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i; -#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; -#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f; -#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); -#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass()); -#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); -#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; -#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a; -#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); -#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); -#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); -#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); int x = param[p].i; +#define PARAM_UINT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); unsigned x = param[p].i; +#define PARAM_BOOL_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); bool x = !!param[p].i; +#define PARAM_NAME_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FName x = ENamedName(param[p].i); +#define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FSoundID x = param[p].i; +#define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); PalEntry x; x.d = param[p].i; +#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); double x = param[p].f; +#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_FLOAT); DAngle x = param[p].f; +#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_STRING); FString x = param[p].s(); +#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass()); +#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(reginfo[p] == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); +#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type *x = (type *)param[p].a; +#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type x = (type )param[p].a; +#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER && AssertObject(param[p].a)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); +#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER && (AssertObject(param[p].a))); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(reginfo[p] == REGT_POINTER); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); // The above, but with an automatically increasing position index. @@ -454,7 +533,7 @@ bool AssertObject(void * ob); #define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type) #define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base) -typedef int(*actionf_p)(VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +typedef int(*actionf_p)(VM_ARGS); struct FieldDesc { @@ -591,7 +670,7 @@ class PFunction; VMFunction *FindVMFunction(PClass *cls, const char *name); #define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name); -FString FStringFormat(VM_ARGS); +FString FStringFormat(VM_ARGS, int offset = 0); unsigned GetVirtualIndex(PClass *cls, const char *funcname); diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index 3424b81d7..0d0e2125f 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -203,7 +203,6 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) { // copy all parameters to the local registers. VMValue &p = params[i]; - assert(*reginfo == p.Type); if (*reginfo < REGT_STRING) { if (*reginfo == REGT_INT) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index c910d61b9..2a67daaec 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -697,7 +697,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) try { VMCycles[0].Unclock(); - numret = static_cast(call)->NativeCall(reg.param + f->NumParam - b, b, returns, C); + numret = static_cast(call)->NativeCall(VM_INVOKE(reg.param + f->NumParam - b, b, returns, C, call->RegTypes)); VMCycles[0].Clock(); } catch (CVMAbortException &err) diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 0f9da7383..e912cdad0 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -296,7 +296,7 @@ int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int nu try { VMCycles[0].Unclock(); - numret = static_cast(func)->NativeCall(params, numparams, returns, numret); + numret = static_cast(func)->NativeCall(VM_INVOKE(params, numparams, returns, numret, func->RegTypes)); VMCycles[0].Clock(); return numret; @@ -571,7 +571,7 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, { if (func->VarFlags & VARF_Native) { - return static_cast(func)->NativeCall(params, numparams, results, numresults); + return static_cast(func)->NativeCall(VM_INVOKE(params, numparams, results, numresults, func->RegTypes)); } else { @@ -730,7 +730,7 @@ void ThrowAbortException(VMScriptFunction *sfunc, VMOP *line, EVMAbortException DEFINE_ACTION_FUNCTION(DObject, ThrowAbortException) { PARAM_PROLOGUE; - FString s = FStringFormat(param, numparam, ret, numret); + FString s = FStringFormat(VM_ARGS_NAMES); ThrowAbortException(X_OTHER, s.GetChars()); return 0; } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 0a06f7b7c..a5b8d875a 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2287,7 +2287,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool TArray rets(1); TArray args; TArray argflags; - TArray argdefaults; + TArray argdefaults; TArray argnames; rets.Clear(); @@ -2495,7 +2495,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool do { int elementcount = 1; - VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. + TypedVMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. if (p->Type != nullptr) { auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index ca9ff6640..c64fcedfd 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -171,10 +171,12 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) PARAM_FLOAT(x); PARAM_FLOAT(y); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)]; - VMVa_List args = { param + 4, 0, numparam - 4 }; + VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo }; screen->DrawTexture(tex, x, y, args); return 0; } @@ -225,10 +227,12 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShape) PARAM_BOOL(animate); PARAM_POINTER(shape, DShape2D); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)]; - VMVa_List args = { param + 3, 0, numparam - 3 }; + VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo }; screen->DrawShape(tex, shape, args); return 0; @@ -418,7 +422,7 @@ int ListGetInt(VMVa_List &tags) { if (tags.curindex < tags.numargs) { - if (tags.args[tags.curindex].Type == REGT_INT) + if (tags.reginfo[tags.curindex] == REGT_INT) { return tags.args[tags.curindex++].i; } @@ -429,11 +433,18 @@ int ListGetInt(VMVa_List &tags) static inline double ListGetDouble(VMVa_List &tags) { - if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_FLOAT) + if (tags.curindex < tags.numargs) { - return tags.args[tags.curindex++].f; + if (tags.reginfo[tags.curindex] == REGT_FLOAT) + { + return tags.args[tags.curindex++].f; + } + if (tags.reginfo[tags.curindex] == REGT_INT) + { + return tags.args[tags.curindex++].i; + } + ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected"); } - ThrowAbortException(X_OTHER, "Invalid parameter in draw function, float expected"); return 0; } diff --git a/src/v_text.cpp b/src/v_text.cpp index 7e4a44b89..fe535b598 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -191,8 +191,10 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawChar) PARAM_FLOAT(y); PARAM_INT(chr); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - VMVa_List args = { param + 5, 0, numparam - 5 }; + VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo }; screen->DrawChar(font, cr, x, y, chr, args); return 0; } @@ -321,8 +323,10 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawText) PARAM_FLOAT(y); PARAM_STRING(chr); + PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array + if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - VMVa_List args = { param + 5, 0, numparam - 5 }; + VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo }; const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars(); screen->DrawText(font, cr, x, y, txt, args); return 0; diff --git a/src/v_video.h b/src/v_video.h index 61185e1b3..71ac19e3d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -287,6 +287,7 @@ struct VMVa_List VMValue *args; int curindex; int numargs; + const uint8_t *reginfo; }; // // VIDEO