Use FxVMFunctionCall in FStateTempCall

- Leveraging FxVMFunctionCall simplifies FinishThingdef() slightly.
This commit is contained in:
Randy Heit 2015-01-03 22:45:11 -06:00
parent 85a2042394
commit 8c105ff3a0
5 changed files with 86 additions and 48 deletions

View file

@ -276,7 +276,7 @@ static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label,
static void FinishThingdef() static void FinishThingdef()
{ {
int errorcount = 0; int errorcount = 0;
unsigned i, j; unsigned i;
int codesize = 0; int codesize = 0;
#if 1 #if 1
@ -289,34 +289,26 @@ static void FinishThingdef()
FStateTempCall *tcall = StateTempCalls[i]; FStateTempCall *tcall = StateTempCalls[i];
VMFunction *func; VMFunction *func;
assert(tcall->Function != NULL); assert(tcall->Call != NULL);
if (tcall->Parameters.Size() == 0) if (tcall->Call->GetArgCount() == 0)
{ {
func = tcall->Function; // There are no arguments, so we can call this function directly
// without wrapping it in an anonymous function.
func = tcall->Call->GetVMFunction();
} }
else else
{ {
FCompileContext ctx(tcall->ActorClass); FCompileContext ctx(tcall->ActorClass);
for (j = 0; j < tcall->Parameters.Size(); ++j) tcall->Call->Resolve(ctx);
{
tcall->Parameters[j]->Resolve(ctx);
}
VMFunctionBuilder buildit; VMFunctionBuilder buildit;
// Allocate registers used to pass parameters in. // Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers) // self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3); buildit.Registers[REGT_POINTER].Get(3);
// Emit code to pass the standard action function parameters.
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0); // Emit a tail call via FxVMFunctionCall
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1); tcall->Call->Emit(&buildit, true);
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2);
// Emit code for action parameters.
for (j = 0; j < tcall->Parameters.Size(); ++j)
{
FxExpression *p = /*new FxParameter*/(tcall->Parameters[j]);
p->Emit(&buildit);
delete p;
}
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0);
VMScriptFunction *sfunc = buildit.MakeFunction(); VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP; sfunc->NumArgs = NAP;
func = sfunc; func = sfunc;
@ -330,6 +322,8 @@ static void FinishThingdef()
codesize += sfunc->CodeSize; codesize += sfunc->CodeSize;
} }
} }
delete tcall->Call;
tcall->Call = NULL;
for (int k = 0; k < tcall->NumStates; ++k) for (int k = 0; k < tcall->NumStates; ++k)
{ {
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);

View file

@ -119,11 +119,10 @@ public:
struct FStateTempCall struct FStateTempCall
{ {
FStateTempCall() : ActorClass(NULL), Function(NULL), FirstState(0), NumStates(0) {} FStateTempCall() : ActorClass(NULL), Call(NULL), FirstState(0), NumStates(0) {}
PClassActor *ActorClass; PClassActor *ActorClass;
VMFunction *Function; class FxVMFunctionCall *Call;
TArray<FxExpression *> Parameters;
int FirstState; int FirstState;
int NumStates; int NumStates;
}; };

View file

@ -798,7 +798,10 @@ public:
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
~FxVMFunctionCall(); ~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build); virtual ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); }
VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; }
}; };
//========================================================================== //==========================================================================

View file

@ -3053,17 +3053,23 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
return NULL; return NULL;
} }
TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes; TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes;
assert(rets.Size() == 1); if (rets.Size() == NULL)
ReturnType = rets[0]; {
// If more types are added to ParseNativeVariable(), add them here too. ReturnType = TypeVoid;
if (rets[0] == TypeSInt32) ValueType = VAL_Int; }
else if (rets[0] == TypeFloat64) ValueType = VAL_Float;
else if (rets[0] == TypeAngle) ValueType = VAL_Angle;
else if (rets[0] == TypeFixed) ValueType = VAL_Fixed;
else else
{ {
ValueType = VAL_Int; ReturnType = rets[0];
assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve"); // If more types are added to ParseNativeVariable(), add them here too.
if (rets[0] == TypeSInt32) ValueType = VAL_Int;
else if (rets[0] == TypeFloat64) ValueType = VAL_Float;
else if (rets[0] == TypeAngle) ValueType = VAL_Angle;
else if (rets[0] == TypeFixed) ValueType = VAL_Fixed;
else
{
ValueType = VAL_Int;
assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve");
}
} }
return this; return this;
} }
@ -3077,6 +3083,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
//========================================================================== //==========================================================================
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
return Emit(build, false);
}
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
{ {
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
int count = ArgList->Size(); int count = ArgList->Size();
@ -3098,13 +3109,27 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{ {
(*ArgList)[i]->Emit(build); (*ArgList)[i]->Emit(build);
} }
// Get a register to store the return value in // Get a constant register for this function
assert(ReturnType != NULL); int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT);
ExpEmit reg(build, ReturnType->GetRegType()); // Emit the call
// Emit the call itself if (tailcall)
build->Emit(OP_CALL_K, build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT), count, 1); { // Tail call
build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); build->Emit(OP_TAIL_K, funcaddr, count, 0);
return reg; return ExpEmit();
}
else if (ReturnType != TypeVoid)
{ // Call, expecting one result
assert(ReturnType != NULL);
ExpEmit reg(build, ReturnType->GetRegType());
build->Emit(OP_CALL_K, funcaddr, count, 1);
build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum);
return reg;
}
else
{ // Call, expecting no results
build->Emit(OP_CALL_K, funcaddr, count, 0);
return ExpEmit();
}
} }
//========================================================================== //==========================================================================

View file

@ -72,24 +72,25 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall
int min_args, max_args; int min_args, max_args;
FString specname = sc.String; FString specname = sc.String;
FArgumentList *args = new FArgumentList;
int special = P_FindLineSpecial(sc.String, &min_args, &max_args); int special = P_FindLineSpecial(sc.String, &min_args, &max_args);
if (special > 0 && min_args >= 0) if (special > 0 && min_args >= 0)
{ {
tcall->Parameters.Push(new FxParameter(new FxConstant(special, sc))); args->Push(new FxParameter(new FxConstant(special, sc)));
i = 0;
// Make this consistent with all other parameter parsing // Make this consistent with all other parameter parsing
if (sc.CheckToken('(')) if (sc.CheckToken('('))
{ {
for (i = 0; i < 5;) while (i < 5)
{ {
tcall->Parameters.Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info)))); args->Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info))));
i++; i++;
if (!sc.CheckToken (',')) break; if (!sc.CheckToken (',')) break;
} }
sc.MustGetToken (')'); sc.MustGetToken (')');
} }
else i=0;
if (i < min_args) if (i < min_args)
{ {
@ -100,7 +101,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag, FStateTempCall
sc.ScriptError ("Too many arguments to %s", specname.GetChars()); sc.ScriptError ("Too many arguments to %s", specname.GetChars());
} }
tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Variants[0].Implementation; tcall->Call = new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc);
return true; return true;
} }
return false; return false;
@ -143,6 +144,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage &
FState state; FState state;
char lastsprite[5] = ""; char lastsprite[5] = "";
FStateTempCall *tcall = NULL; FStateTempCall *tcall = NULL;
FArgumentList *args = NULL;
sc.MustGetStringName ("{"); sc.MustGetStringName ("{");
sc.SetEscape(false); // disable escape sequences in the state parser sc.SetEscape(false); // disable escape sequences in the state parser
@ -325,8 +327,19 @@ do_stop:
PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true)); PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(FName(sc.String, true), true));
if (afd != NULL) if (afd != NULL)
{ {
tcall->Function = afd->Variants[0].Implementation; // When creating the FxVMFunctionCall, we only pass args if there are any.
ParseFunctionParameters(sc, bag.Info, tcall->Parameters, afd, statestring, &bag.statedef); // So if the previous call had no args, then we can use the argument list
// allocated for it. Otherwise, we need to create a new one.
if (args == NULL)
{
args = new FArgumentList;
}
ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef);
tcall->Call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc);
if (args->Size() > 0)
{
args = NULL;
}
goto endofstate; goto endofstate;
} }
sc.ScriptError("Invalid state parameter %s\n", sc.String); sc.ScriptError("Invalid state parameter %s\n", sc.String);
@ -339,7 +352,7 @@ endofstate:
sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
count = -count; count = -count;
} }
if (tcall->Function != NULL) if (tcall->Call != NULL)
{ {
tcall->ActorClass = actor; tcall->ActorClass = actor;
tcall->FirstState = bag.statedef.GetStateCount() - count; tcall->FirstState = bag.statedef.GetStateCount() - count;
@ -353,6 +366,10 @@ endofstate:
{ {
delete tcall; delete tcall;
} }
if (args != NULL)
{
delete args;
}
sc.SetEscape(true); // re-enable escape sequences sc.SetEscape(true); // re-enable escape sequences
} }