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