Implement tail calls in generated bytecode classes.
This commit is contained in:
@@ -101,10 +101,10 @@ public class LuaClosure extends LuaFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Varargs invoke(Varargs varargs) {
|
public final Varargs invoke(Varargs varargs) {
|
||||||
return oninvoke( varargs ).eval();
|
return onInvoke( varargs ).eval();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Varargs oninvoke(Varargs varargs) {
|
public Varargs onInvoke(Varargs varargs) {
|
||||||
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
LuaValue[] stack = new LuaValue[p.maxstacksize];
|
||||||
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
|
||||||
for ( int i=0; i<p.numparams; i++ )
|
for ( int i=0; i<p.numparams; i++ )
|
||||||
|
|||||||
@@ -424,9 +424,17 @@ public class LuaValue extends Varargs {
|
|||||||
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3);
|
default: return new ArrayVarargs(new LuaValue[] {v1,v2},v3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tail call support
|
||||||
public static Varargs tailcallOf(LuaValue func, Varargs args) {
|
public static Varargs tailcallOf(LuaValue func, Varargs args) {
|
||||||
return new TailcallVarargs(func, args);
|
return new TailcallVarargs(func, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called by TailcallVarargs to invoke the function once.
|
||||||
|
// may return TailcallVarargs to be evaluated by the caller.
|
||||||
|
public Varargs onInvoke(Varargs args) {
|
||||||
|
return invoke(args);
|
||||||
|
}
|
||||||
|
|
||||||
// empty varargs
|
// empty varargs
|
||||||
private static final class None extends LuaNil {
|
private static final class None extends LuaNil {
|
||||||
|
|||||||
@@ -32,22 +32,24 @@ public class TailcallVarargs extends Varargs {
|
|||||||
this.args = args;
|
this.args = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTailcall() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Varargs eval() {
|
public Varargs eval() {
|
||||||
TailcallVarargs nextcall = this;
|
while ( result == null ) {
|
||||||
do {
|
Varargs r = func.onInvoke(args);
|
||||||
LuaValue func = nextcall.func;
|
if (r.isTailcall()) {
|
||||||
Varargs args = nextcall.args;
|
TailcallVarargs t = (TailcallVarargs) r;
|
||||||
nextcall = null;
|
func = t.func;
|
||||||
Varargs r = func.isclosure()?
|
args = t.args;
|
||||||
((LuaClosure) func).oninvoke(args):
|
}
|
||||||
func.invoke(args);
|
else {
|
||||||
|
result = r;
|
||||||
if (r instanceof TailcallVarargs)
|
func = null;
|
||||||
nextcall = (TailcallVarargs)r;
|
args = null;
|
||||||
else
|
}
|
||||||
this.result = r;
|
}
|
||||||
|
|
||||||
} while (nextcall != null);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,13 @@ public abstract class Varargs {
|
|||||||
*/
|
*/
|
||||||
public Varargs eval() { return this; }
|
public Varargs eval() { return this; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this is a TailcallVarargs
|
||||||
|
* @return true if a tail call, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isTailcall() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// utilities to get specific arguments and type-check them.
|
// utilities to get specific arguments and type-check them.
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -49,17 +49,31 @@ abstract public class VarArgFunction extends LibFunction {
|
|||||||
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
|
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override and implement for the best performance.
|
||||||
|
* May not have expected behavior for tail calls.
|
||||||
|
* Should not be used if either:
|
||||||
|
* - function needs to be used as a module
|
||||||
|
* - function has a possibility of returning a TailcallVarargs
|
||||||
|
* @param args the arguments to the function call.
|
||||||
|
*/
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaThread.onCall(this);
|
LuaThread.onCall(this);
|
||||||
try {
|
try {
|
||||||
return onInvoke(args);
|
return this.onInvoke(args).eval();
|
||||||
} finally {
|
} finally {
|
||||||
LuaThread.onReturn();
|
LuaThread.onReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Varargs onInvoke(Varargs args) {
|
/**
|
||||||
return NONE;
|
* Override to provide a call implementation that runs in an environment
|
||||||
|
* that can participate in setfenv, and behaves as expected
|
||||||
|
* when returning TailcallVarargs.
|
||||||
|
* @param args the arguments to the function call.
|
||||||
|
*/
|
||||||
|
public Varargs onInvoke(Varargs args) {
|
||||||
|
return invoke(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class JavaBuilder {
|
|||||||
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
|
private static final ObjectType[] RETURN_TYPE_N = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
|
||||||
private static final Type[][] ARG_TYPES_N = { {}, {TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_VARARGS}, };
|
private static final Type[][] ARG_TYPES_N = { {}, {TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_LUAVALUE,TYPE_LUAVALUE,TYPE_LUAVALUE}, {TYPE_VARARGS}, };
|
||||||
private static final String[][] ARG_NAMES_N = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
|
private static final String[][] ARG_NAMES_N = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
|
||||||
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "invoke", };
|
private static final String[] METH_NAME_N = { "call", "call", "call", "call", "onInvoke", };
|
||||||
|
|
||||||
// varable naming
|
// varable naming
|
||||||
private static final String PREFIX_CONSTANT = "k";
|
private static final String PREFIX_CONSTANT = "k";
|
||||||
@@ -156,8 +156,12 @@ public class JavaBuilder {
|
|||||||
superclassType = SUPERTYPE_VARARGS;
|
superclassType = SUPERTYPE_VARARGS;
|
||||||
for ( int i=0, n=p.code.length; i<n; i++ ) {
|
for ( int i=0, n=p.code.length; i<n; i++ ) {
|
||||||
int inst = p.code[i];
|
int inst = p.code[i];
|
||||||
if ( Lua.GET_OPCODE(inst) == Lua.OP_RETURN && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2) )
|
int o = Lua.GET_OPCODE(inst);
|
||||||
|
if ( (o == Lua.OP_TAILCALL) ||
|
||||||
|
((o == Lua.OP_RETURN) && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2)) ) {
|
||||||
superclassType = SUPERTYPE_VARARGS;
|
superclassType = SUPERTYPE_VARARGS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create class generator
|
// create class generator
|
||||||
|
|||||||
Reference in New Issue
Block a user