- 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.
This commit is contained in:
Christoph Oelckers 2018-11-18 19:31:13 +01:00
parent a981737855
commit a9ec819557
18 changed files with 265 additions and 164 deletions

View file

@ -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;
}

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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<PSymbolConstNumeric*>(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<PClass *>(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<PClass *>(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));

View file

@ -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)

View file

@ -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<ExpEmit>
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)
{

View file

@ -169,11 +169,22 @@ class FunctionCallEmitter
// std::function and TArray are not compatible so this has to use std::vector instead.
std::vector<std::function<int(VMFunctionBuilder *)>> emitters;
TArray<std::pair<int, int>> returns;
TArray<uint8_t> 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;

View file

@ -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;
}

View file

@ -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:

View file

@ -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<VMValue> DefaultArgs;
TArray<TypedVMValue> 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 <x> at position <p>
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);

View file

@ -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)

View file

@ -697,7 +697,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
try
{
VMCycles[0].Unclock();
numret = static_cast<VMNativeFunction *>(call)->NativeCall(reg.param + f->NumParam - b, b, returns, C);
numret = static_cast<VMNativeFunction *>(call)->NativeCall(VM_INVOKE(reg.param + f->NumParam - b, b, returns, C, call->RegTypes));
VMCycles[0].Clock();
}
catch (CVMAbortException &err)

View file

@ -296,7 +296,7 @@ int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int nu
try
{
VMCycles[0].Unclock();
numret = static_cast<VMNativeFunction *>(func)->NativeCall(params, numparams, returns, numret);
numret = static_cast<VMNativeFunction *>(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<VMNativeFunction *>(func)->NativeCall(params, numparams, results, numresults);
return static_cast<VMNativeFunction *>(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;
}

View file

@ -2287,7 +2287,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
TArray<PType *> rets(1);
TArray<PType *> args;
TArray<uint32_t> argflags;
TArray<VMValue> argdefaults;
TArray<TypedVMValue> argdefaults;
TArray<FName> 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);

View file

@ -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;
}

View file

@ -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;

View file

@ -287,6 +287,7 @@ struct VMVa_List
VMValue *args;
int curindex;
int numargs;
const uint8_t *reginfo;
};
//
// VIDEO