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);
|
p->Emit(&buildit);
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
buildit.Emit(OP_CALL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0);
|
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(tcall->Function, ATAG_OBJECT), NAP + j, 0);
|
||||||
buildit.Emit(OP_RET, 0, REGT_NIL, 0);
|
|
||||||
VMScriptFunction *sfunc = buildit.MakeFunction();
|
VMScriptFunction *sfunc = buildit.MakeFunction();
|
||||||
sfunc->NumArgs = NAP;
|
sfunc->NumArgs = NAP;
|
||||||
func = sfunc;
|
func = sfunc;
|
||||||
|
|
|
@ -430,7 +430,7 @@ size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
|
||||||
{
|
{
|
||||||
ParamChange(1);
|
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);
|
ParamChange(-opb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
#define I24 MODE_ABCJOINT
|
#define I24 MODE_ABCJOINT
|
||||||
#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED
|
#define I8 MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED
|
||||||
#define __BCP MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM
|
#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 RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ
|
||||||
#define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ
|
#define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ
|
||||||
#define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM
|
#define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM
|
||||||
|
@ -215,9 +217,14 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_CALL_K:
|
case OP_CALL_K:
|
||||||
|
case OP_TAIL_K:
|
||||||
callfunc = (VMFunction *)func->KonstA[code[i].a].o;
|
callfunc = (VMFunction *)func->KonstA[code[i].a].o;
|
||||||
callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]";
|
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;
|
break;
|
||||||
|
|
||||||
case OP_RET:
|
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);
|
printf_wrapper(out, "%d\n", code[i].i24);
|
||||||
}
|
}
|
||||||
else if (code[i].op == OP_CALL_K)
|
else
|
||||||
{
|
{
|
||||||
printf_wrapper(out, "%d,%d,%d [%p]\n", code[i].a, code[i].b, code[i].c, callfunc);
|
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
|
else
|
||||||
{
|
{
|
||||||
printf_wrapper(out, "%d,%d,%d\n", code[i].a, code[i].b, code[i].c);
|
printf_wrapper(out, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,6 +539,43 @@ begin:
|
||||||
pc += C; // Skip RESULTs
|
pc += C; // Skip RESULTs
|
||||||
}
|
}
|
||||||
NEXTOP;
|
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):
|
OP(RET):
|
||||||
if (B == REGT_NIL)
|
if (B == REGT_NIL)
|
||||||
{ // No return values
|
{ // 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(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, call, RPI8I8), // Call function pkA with parameter count B and expected result count C
|
||||||
xx(CALL_K, call, KPI8I8),
|
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(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(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
|
xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC
|
||||||
|
|
Loading…
Reference in a new issue