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()
{
int errorcount = 0;
unsigned i, j;
unsigned i;
int codesize = 0;
#if 1
@ -289,34 +289,26 @@ static void FinishThingdef()
FStateTempCall *tcall = StateTempCalls[i];
VMFunction *func;
assert(tcall->Function != NULL);
if (tcall->Parameters.Size() == 0)
assert(tcall->Call != NULL);
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
{
FCompileContext ctx(tcall->ActorClass);
for (j = 0; j < tcall->Parameters.Size(); ++j)
{
tcall->Parameters[j]->Resolve(ctx);
}
tcall->Call->Resolve(ctx);
VMFunctionBuilder buildit;
// Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3);
// Emit code to pass the standard action function parameters.
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0);
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1);
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);
// Emit a tail call via FxVMFunctionCall
tcall->Call->Emit(&buildit, true);
VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP;
func = sfunc;
@ -330,6 +322,8 @@ static void FinishThingdef()
codesize += sfunc->CodeSize;
}
}
delete tcall->Call;
tcall->Call = NULL;
for (int k = 0; k < tcall->NumStates; ++k)
{
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);

View file

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

View file

@ -798,7 +798,10 @@ public:
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
~FxVMFunctionCall();
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;
}
TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes;
assert(rets.Size() == 1);
ReturnType = rets[0];
// 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;
if (rets.Size() == NULL)
{
ReturnType = TypeVoid;
}
else
{
ValueType = VAL_Int;
assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve");
ReturnType = rets[0];
// 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;
}
@ -3077,6 +3083,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
//==========================================================================
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
return Emit(build, false);
}
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
{
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
int count = ArgList->Size();
@ -3098,13 +3109,27 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
(*ArgList)[i]->Emit(build);
}
// Get a register to store the return value in
assert(ReturnType != NULL);
ExpEmit reg(build, ReturnType->GetRegType());
// Emit the call itself
build->Emit(OP_CALL_K, build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT), count, 1);
build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum);
return reg;
// Get a constant register for this function
int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT);
// Emit the call
if (tailcall)
{ // Tail call
build->Emit(OP_TAIL_K, funcaddr, count, 0);
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;
FString specname = sc.String;
FArgumentList *args = new FArgumentList;
int special = P_FindLineSpecial(sc.String, &min_args, &max_args);
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
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++;
if (!sc.CheckToken (',')) break;
}
sc.MustGetToken (')');
}
else i=0;
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());
}
tcall->Function = FindGlobalActionFunction("A_CallSpecial")->Variants[0].Implementation;
tcall->Call = new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc);
return true;
}
return false;
@ -143,6 +144,7 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage &
FState state;
char lastsprite[5] = "";
FStateTempCall *tcall = NULL;
FArgumentList *args = NULL;
sc.MustGetStringName ("{");
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));
if (afd != NULL)
{
tcall->Function = afd->Variants[0].Implementation;
ParseFunctionParameters(sc, bag.Info, tcall->Parameters, afd, statestring, &bag.statedef);
// When creating the FxVMFunctionCall, we only pass args if there are any.
// 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;
}
sc.ScriptError("Invalid state parameter %s\n", sc.String);
@ -339,7 +352,7 @@ endofstate:
sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
count = -count;
}
if (tcall->Function != NULL)
if (tcall->Call != NULL)
{
tcall->ActorClass = actor;
tcall->FirstState = bag.statedef.GetStateCount() - count;
@ -353,6 +366,10 @@ endofstate:
{
delete tcall;
}
if (args != NULL)
{
delete args;
}
sc.SetEscape(true); // re-enable escape sequences
}