mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-12 07:34:50 +00:00
Use FxVMFunctionCall in FStateTempCall
- Leveraging FxVMFunctionCall simplifies FinishThingdef() slightly.
This commit is contained in:
parent
85a2042394
commit
8c105ff3a0
5 changed files with 86 additions and 48 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue