mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-15 17:02:05 +00:00
- Added the TAIL instruction to perform a CALL and a RET in the same instruction. The called
function will pass its results directly to this function's caller. Eventually, this should be changed to do a proper tail call for scripted functions. SVN r3769 (scripting)
This commit is contained in:
parent
644f0c0e05
commit
e1a2f3b546
5 changed files with 58 additions and 9 deletions
|
@ -300,8 +300,7 @@ static void FinishThingdef()
|
|||
p->Emit(&buildit);
|
||||
delete p;
|
||||
}
|
||||
buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0);
|
||||
buildit.Emit(OP_RET, 0, REGT_NIL, 0);
|
||||
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0);
|
||||
VMScriptFunction *sfunc = buildit.MakeFunction();
|
||||
sfunc->NumArgs = NAP;
|
||||
func = sfunc;
|
||||
|
|
|
@ -430,7 +430,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
|||
{
|
||||
ParamChange(1);
|
||||
}
|
||||
else if (opcode == OP_CALL || opcode == OP_CALL_K)
|
||||
else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K)
|
||||
{
|
||||
ParamChange(-opb);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#define I24 MODE_ABCJOINT
|
||||
#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED
|
||||
#define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM
|
||||
#define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED
|
||||
#define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED
|
||||
#define RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ
|
||||
#define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ
|
||||
#define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM
|
||||
|
@ -215,9 +217,14 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
break;
|
||||
|
||||
case OP_CALL_K:
|
||||
case OP_TAIL_K:
|
||||
callfunc = (VMFunction *)func->KonstA[code[i].a].o;
|
||||
callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]";
|
||||
col = printf_wrapper(out, "%.23s,%d,%d", callname, code[i].b, code[i].c);
|
||||
col = printf_wrapper(out, "%.23s,%d", callname, code[i].b);
|
||||
if (code[i].op == OP_CALL_K)
|
||||
{
|
||||
printf_wrapper(out, ",%d", code[i].c);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_RET:
|
||||
|
@ -316,13 +323,17 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
{
|
||||
printf_wrapper(out, "%d\n", code[i].i24);
|
||||
}
|
||||
else if (code[i].op == OP_CALL_K)
|
||||
{
|
||||
printf_wrapper(out, "%d,%d,%d [%p]\n", code[i].a, code[i].b, code[i].c, callfunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c);
|
||||
printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c);
|
||||
if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K)
|
||||
{
|
||||
printf_wrapper(out, " [%p]\n", callfunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_wrapper(out, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -539,6 +539,43 @@ begin:
|
|||
pc += C; // Skip RESULTs
|
||||
}
|
||||
NEXTOP;
|
||||
OP(TAIL_K):
|
||||
ASSERTKA(a);
|
||||
assert(konstatag[a] == ATAG_OBJECT);
|
||||
ptr = konsta[a].o;
|
||||
goto Do_TAILCALL;
|
||||
OP(TAIL):
|
||||
ASSERTA(a);
|
||||
ptr = reg.a[a];
|
||||
Do_TAILCALL:
|
||||
assert(B <= f->NumParam);
|
||||
assert(C <= MAX_RETURNS);
|
||||
{
|
||||
VMFunction *call = (VMFunction *)ptr;
|
||||
|
||||
if (call->Native)
|
||||
{
|
||||
return static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret);
|
||||
}
|
||||
else
|
||||
{ // FIXME: Not a true tail call
|
||||
VMScriptFunction *script = static_cast<VMScriptFunction *>(call);
|
||||
VMFrame *newf = stack->AllocFrame(script);
|
||||
VMFillParams(reg.param + f->NumParam - B, newf, B);
|
||||
try
|
||||
{
|
||||
numret = Exec(stack, script->Code, ret, numret);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
stack->PopFrame();
|
||||
throw;
|
||||
}
|
||||
stack->PopFrame();
|
||||
return numret;
|
||||
}
|
||||
}
|
||||
NEXTOP;
|
||||
OP(RET):
|
||||
if (B == REGT_NIL)
|
||||
{ // No return values
|
||||
|
|
|
@ -77,6 +77,8 @@ xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=r
|
|||
xx(PARAMI, parami, I24), // push immediate, signed integer for function call
|
||||
xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C
|
||||
xx(CALL_K, call, KPI8I8),
|
||||
xx(TAIL, tail, RPI8), // Call+Ret in a single instruction
|
||||
xx(TAIL_K, tail, KPI8),
|
||||
xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL)
|
||||
xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning
|
||||
xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC
|
||||
|
|
Loading…
Reference in a new issue