Improve handling of tail calls in debug info

This commit is contained in:
James Roseborough
2009-04-08 14:40:52 +00:00
parent a91cd3dfee
commit 71f539ab2d
4 changed files with 63 additions and 53 deletions

View File

@@ -483,48 +483,36 @@ public class DebugLib extends LFunction {
private static StackInfo[] getstackinfo(LuaState vm, int level, int countlevels) { private static StackInfo[] getstackinfo(LuaState vm, int level, int countlevels) {
StackInfo[] si = new StackInfo[countlevels]; StackInfo[] si = new StackInfo[countlevels];
int i = 0; int i = 0;
LClosure prevclosure = null;
for (int j=vm.cc; j>=0; --j) { for (int j=vm.cc; j>=0; --j) {
CallInfo ci = vm.calls[j]; CallInfo ci = vm.calls[j];
int instr = ci.closure.p.code[ci.pc>0? ci.pc-1: 0]; LFunction f = ci.currentfunc(vm);
// java function? // java, or tailcall?
if ( Lua.GET_OPCODE(instr) == Lua.OP_CALL ) { if ( f != null && (! f.isClosure() || f!=prevclosure) ) {
int a = Lua.GETARG_A(instr); if ( (level--) <= 0 ) {
LValue f = vm.stack[ci.base + a]; si[i++] = new StackInfo( vm, ci, ci.currentfunca(vm), null, f);
if ( f.isFunction() ) { if ( i >= countlevels )
return si;
}
}
// add the lua closure // add the lua closure
if ( j < vm.cc ) {
if ( (level--) <= 0 ) { if ( (level--) <= 0 ) {
CallInfo ci1 = vm.calls[j+1]; if (j>0 && vm.calls[j-1].currentfunc(vm) == ci.closure) {
LValue f1 = vm.calls[j+1].closure; CallInfo caller = vm.calls[j-1];
if ( f != f1 ) int callera = caller.currentfunca(vm);
a = ci1.resultbase-ci.base; si[i++] = new StackInfo( vm, caller, callera, ci, ci.closure);
si[i++] = new StackInfo( vm, ci, a, ci1, null); } else {
si[i++] = new StackInfo( vm, null, -1, ci, ci.closure);
}
if ( i >= countlevels ) if ( i >= countlevels )
return si; return si;
} }
prevclosure = ci.closure;
} }
// is there also a java call?
if ( ! f.isClosure() ) {
if ( (level--) <= 0 ) {
si[i++] = new StackInfo( vm, ci, a, null, (LFunction) f);
if ( i >= countlevels )
return si;
}
}
// TODO: tail calls, for loops
}
}
}
// first call is a plain call with no enclosing frame
if ( (level--) <= 0 )
si[i++] = new StackInfo(vm, null, -1, vm.calls[0], null);
return si; return si;
} }

View File

@@ -54,4 +54,30 @@ public class CallInfo {
return -1; return -1;
} }
/**
* @param vm
* @return current function executing, or null
*/
public LFunction currentfunc(LuaState vm) {
int a = currentfunca(vm);
if ( a >= 0 ) {
LValue v = vm.stack[base + a];
if ( v.isFunction() )
return (LFunction) v;
}
return null;
}
/**
* @param vm
* @return register of the current function executing, or null
*/
public int currentfunca(LuaState vm) {
int i = closure.p.code[pc>0? pc-1: 0];
int op = Lua.GET_OPCODE(i);
if ( op == Lua.OP_CALL || op == Lua.OP_TAILCALL )
return Lua.GETARG_A(i);
return -1;
}
} }

View File

@@ -53,14 +53,14 @@ public class LuaErrorException extends RuntimeException {
* @param message message to supply * @param message message to supply
*/ */
public LuaErrorException(String message) { public LuaErrorException(String message) {
this(null, message, 1); this(null, message, -1);
} }
/** /**
* Construct the message around a specific vm and with a particular level of debug info * Construct the message around a specific vm and with a particular level of debug info
* @param vm * @param vm
* @param message * @param message
* @param level * @param level 0 for no message, >=1 for current call or above, -1 for most recent lua call
*/ */
public LuaErrorException(LuaState vm, String message, int level) { public LuaErrorException(LuaState vm, String message, int level) {
super( addLineInfo( vm, message, level ) ); super( addLineInfo( vm, message, level ) );
@@ -74,7 +74,7 @@ public class LuaErrorException extends RuntimeException {
* @return * @return
*/ */
private static String addLineInfo(LuaState vm, String message, int level) { private static String addLineInfo(LuaState vm, String message, int level) {
if ( level < 1 || message == null ) if ( level == 0 || message == null )
return message; return message;
if ( vm == null ) { if ( vm == null ) {
if ( LThread.running != null ) if ( LThread.running != null )

View File

@@ -1080,26 +1080,22 @@ public class LuaState extends Lua {
/** /**
* Get the file line number info for a particular call frame. * Get the file line number info for a particular call frame.
* @param cindex index into call stack * @param cindex index into call stack, or -1 to get first lua location
* @return * @return
*/ */
protected String getFileLine(int level) { protected String getFileLine(int level) {
LClosure c = null;
for (int j=cc; j>=0; --j) { for (int j=cc; j>=0; --j) {
CallInfo ci = calls[j]; CallInfo ci = calls[j];
int instr = ci.closure.p.code[ci.pc>0? ci.pc-1: 0]; LFunction f = ci.currentfunc(this);
if ( Lua.GET_OPCODE(instr) == Lua.OP_CALL ) { if ( f != null && (!f.isClosure() || f!=c) ) {
int a = Lua.GETARG_A(instr); if ( level != -1 && (level--) <= 0 ) {
LValue f = stack[ci.base + a];
if ( f.isFunction() ) {
if ( ! f.isClosure() ) {
if ( (level--) <= 0 ) {
return "[Java]: "+f.toString(); return "[Java]: "+f.toString();
} }
} }
c = ci.closure;
if ( (level--) <= 0 ) { if ( (level--) <= 0 ) {
return ci.closure.p.sourceshort()+":"+ci.currentline(); return c.p.sourceshort()+":"+ci.currentline();
}
}
} }
} }
return ""; return "";
@@ -1121,7 +1117,7 @@ public class LuaState extends Lua {
* Raises an error with the default level. * Raises an error with the default level.
*/ */
public void error(String message) { public void error(String message) {
throw new LuaErrorException( this, message, 1 ); throw new LuaErrorException( this, message, -1 );
} }
/** /**
@@ -2462,7 +2458,7 @@ public class LuaState extends Lua {
case LUA_HOOKCOUNT: this.pushstring("count"); break; case LUA_HOOKCOUNT: this.pushstring("count"); break;
case LUA_HOOKCALL: this.pushstring("call"); break; case LUA_HOOKCALL: this.pushstring("call"); break;
case LUA_HOOKRET: this.pushstring("return"); break; case LUA_HOOKRET: this.pushstring("return"); break;
case LUA_HOOKTAILRET: this.pushstring("return"); break; case LUA_HOOKTAILRET: this.pushstring("tail return"); break;
default: default:
lineval = LInteger.valueOf(line); lineval = LInteger.valueOf(line);
this.pushstring("line"); this.pushstring("line");