- implemented VMCallWithDefaults and used it for all calls with variable arguments.

This isn't used for the 3 action function calls because it requires an array allocation which would be a bit too costly for something as frequently called as action functions.
They will need a different approach.
This commit is contained in:
Christoph Oelckers 2018-11-16 19:18:33 +01:00
parent 6d7710165c
commit 97573a0452
6 changed files with 23 additions and 12 deletions

View File

@ -175,13 +175,13 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
if (stateret == nullptr)
{
VMCallWithDefaults(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0);
VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0);
}
else
{
VMReturn ret;
ret.PointerAt((void **)stateret);
VMCallWithDefaults(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1);
VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1);
}
}
catch (CVMAbortException &err)

View File

@ -477,7 +477,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
}
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
VMCallWithDefaults(func->Variants[0].Implementation, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
if (cls->IsDescendantOf("ListMenuItemSelectable"))
@ -917,7 +917,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
VMCallWithDefaults(func->Variants[0].Implementation, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func->Variants[0].Implementation, params, nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
success = true;

View File

@ -5448,7 +5448,7 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args)
// The return value can be the same types as the parameter types, plus void
if (func->Proto->ReturnTypes.Size() == 0)
{
VMCallWithDefaults(func, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func, params, nullptr, 0);
}
else
{
@ -5470,20 +5470,20 @@ static int ScriptCall(AActor *activator, unsigned argc, int32_t *args)
{
double d;
VMReturn ret(&d);
VMCallWithDefaults(func, &params[0], params.Size(), &ret, 1);
VMCallWithDefaults(func, params, &ret, 1);
retval = DoubleToACS(d);
}
else if (rettype == TypeString)
{
FString d;
VMReturn ret(&d);
VMCallWithDefaults(func, &params[0], params.Size(), &ret, 1);
VMCallWithDefaults(func, params, &ret, 1);
retval = GlobalACSStrings.AddString(d);
}
else
{
// All other return values can not be handled so ignore them.
VMCallWithDefaults(func, &params[0], params.Size(), nullptr, 0);
VMCallWithDefaults(func, params, nullptr, 0);
}
}
}

View File

@ -170,7 +170,7 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state)
try
{
state->CheckCallerType(actor, this);
VMCallWithDefaults(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
VMCallAction(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
}
catch (CVMAbortException &err)
{

View File

@ -209,8 +209,6 @@ struct VMValue
const FString *sp;
};
// Unfortunately, FString cannot be used directly.
// Fortunately, it is relatively simple.
const FString &s() const { return *sp; }
VMValue()
@ -376,8 +374,9 @@ private:
};
int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/);
int VMCallWithDefaults(VMFunction *func, TArray<VMValue> &params, VMReturn *results, int numresults/*, VMException **trap = NULL*/);
inline int VMCallWithDefaults(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/)
inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap = NULL*/)
{
return VMCall(func, params, numparams, results, numresults);
}

View File

@ -577,6 +577,18 @@ int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results,
#endif
}
int VMCallWithDefaults(VMFunction *func, TArray<VMValue> &params, VMReturn *results, int numresults/*, VMException **trap = NULL*/)
{
if (func->DefaultArgs.Size() > params.Size())
{
auto oldp = params.Size();
params.Resize(func->DefaultArgs.Size());
memcpy(&params[oldp], &func->DefaultArgs[oldp], (params.Size() - oldp) * sizeof(VMValue));
}
return VMCall(func, params.Data(), params.Size(), results, numresults);
}
// Exception stuff for the VM is intentionally placed there, because having this in vmexec.cpp would subject it to inlining
// which we do not want because it increases the local stack requirements of Exec which are already too high.
FString CVMAbortException::stacktrace;