- build full argument lists for action function calls.

This uses one static global array to avoid frequent reallocations.
This commit is contained in:
Christoph Oelckers 2018-11-16 20:38:52 +01:00
parent 97573a0452
commit 16053c7cdb
3 changed files with 70 additions and 13 deletions

View file

@ -148,6 +148,7 @@ void FState::CheckCallerType(AActor *self, AActor *stateowner)
} }
} }
TArray<VMValue> actionParams;
bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret)
{ {
@ -155,7 +156,6 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
{ {
ActionCycles.Clock(); ActionCycles.Clock();
VMValue params[3] = { self, stateowner, VMValue(info) };
// If the function returns a state, store it at *stateret. // If the function returns a state, store it at *stateret.
// If it doesn't return a state but stateret is non-nullptr, we need // If it doesn't return a state but stateret is non-nullptr, we need
// to set *stateret to nullptr. // to set *stateret to nullptr.
@ -169,19 +169,36 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info,
stateret = nullptr; stateret = nullptr;
} }
} }
VMReturn ret;
ret.PointerAt((void **)stateret);
try try
{ {
CheckCallerType(self, stateowner); CheckCallerType(self, stateowner);
if (stateret == nullptr) // Build the parameter array. Action functions have never any explicit parameters but need to pass the defaults
// and fill in the implicit arguments of the called function.
if (ActionFunc->DefaultArgs.Size() > 0)
{ {
VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); auto index = actionParams.Append(ActionFunc->DefaultArgs);
if (ActionFunc->ImplicitArgs >= 1)
{
actionParams[index] = self;
}
if (ActionFunc->ImplicitArgs == 3)
{
actionParams[index + 1] = stateowner;
actionParams[index + 2] = VMValue(info);
}
VMCallAction(ActionFunc, &actionParams[index], ActionFunc->DefaultArgs.Size(), &ret, stateret != nullptr);
actionParams.Clamp(index);
} }
else else
{ {
VMReturn ret; VMValue params[3] = { self, stateowner, VMValue(info) };
ret.PointerAt((void **)stateret); VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, stateret != nullptr);
VMCallAction(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1);
} }
} }
catch (CVMAbortException &err) catch (CVMAbortException &err)

View file

@ -96,12 +96,13 @@ static FRandom pr_bfgselfdamage("BFGSelfDamage");
// until there is no next state // until there is no next state
// //
//========================================================================== //==========================================================================
extern TArray<VMValue> actionParams; // this can use the same storage as CallAction
bool AStateProvider::CallStateChain (AActor *actor, FState *state) bool AStateProvider::CallStateChain (AActor *actor, FState *state)
{ {
INTBOOL result = false; INTBOOL result = false;
int counter = 0; int counter = 0;
VMValue params[3] = { actor, this, 0 };
// We accept return types of `state`, `(int|bool)` or `state, (int|bool)`. // We accept return types of `state`, `(int|bool)` or `state, (int|bool)`.
// The last one is for the benefit of A_Warp and A_Teleport. // The last one is for the benefit of A_Warp and A_Teleport.
@ -139,7 +140,6 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state)
VMReturn *wantret; VMReturn *wantret;
FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON }; FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON };
params[2] = VMValue(&stp);
retval = true; // assume success retval = true; // assume success
wantret = NULL; // assume no return value wanted wantret = NULL; // assume no return value wanted
numret = 0; numret = 0;
@ -167,10 +167,33 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state)
wantret = &ret[1]; wantret = &ret[1];
numret = 1; numret = 1;
} }
try try
{ {
state->CheckCallerType(actor, this); state->CheckCallerType(actor, this);
VMCallAction(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
if (state->ActionFunc->DefaultArgs.Size() > 0)
{
auto index = actionParams.Append(state->ActionFunc->DefaultArgs);
if (state->ActionFunc->ImplicitArgs >= 1)
{
actionParams[index] = actor;
}
if (state->ActionFunc->ImplicitArgs == 3)
{
actionParams[index + 1] = this;
actionParams[index + 2] = VMValue(&stp);
}
VMCallAction(state->ActionFunc, &actionParams[index], state->ActionFunc->DefaultArgs.Size(), wantret, numret);
actionParams.Clamp(index);
}
else
{
VMValue params[3] = { actor, this, VMValue(&stp) };
VMCallAction(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret);
}
} }
catch (CVMAbortException &err) catch (CVMAbortException &err)
{ {

View file

@ -278,13 +278,30 @@ public:
return Count++; return Count++;
} }
void Append(const TArray<T> &item) unsigned Append(const TArray<T> &item)
{ {
unsigned start = Reserve(item.Size()); unsigned start = Count;
Grow(item.Size());
for (unsigned i = 0; i < item.Size(); i++) for (unsigned i = 0; i < item.Size(); i++)
{ {
Array[start + i] = item[i]; new(&Array[start + i]) T(item[i]);
} }
return start;
}
unsigned Append(TArray<T> &&item)
{
unsigned start = Count;
Grow(item.Size());
for (unsigned i = 0; i < item.Size(); i++)
{
new(&Array[start + i]) T(std::move(item[i]));
}
return start;
} }
bool Pop () bool Pop ()