mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-13 16:07:55 +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()
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue