Improve call hooks, stack trace and getinfo reporting.

This commit is contained in:
James Roseborough
2009-04-04 22:00:37 +00:00
parent 7d3d4d9f01
commit e9847bb70d
2 changed files with 103 additions and 35 deletions

View File

@@ -31,6 +31,7 @@ import org.luaj.vm.LPrototype;
import org.luaj.vm.LString;
import org.luaj.vm.LTable;
import org.luaj.vm.LValue;
import org.luaj.vm.Lua;
import org.luaj.vm.LuaErrorException;
import org.luaj.vm.LuaState;
@@ -206,30 +207,46 @@ public class DebugLib extends LFunction {
vm.remove(2);
}
String what = vm.optstring(3, "nSluf");
// find the closure or function
if ( vm.isnumber(2) ) {
ci = this.getcallinfo(vm, threadVm, vm.tointeger(2));
if ( ci == null ) {
Object o = getcallinfoorfunction(threadVm, vm.tointeger(2));
if ( o == null ) {
vm.resettop();
return;
}
closure = ci.closure;
if ( o instanceof CallInfo ) {
ci = (CallInfo) o;
closure = ci.closure;
} else {
func = (LFunction) o;
}
} else {
func = vm.checkfunction(2);
if ( func instanceof LClosure )
closure = (LClosure) func;
}
vm.resettop();
// look up info
LTable info = new LTable();
vm.pushlvalue(info);
for (int i = 0, n = what.length(); i < n; i++) {
switch (what.charAt(i)) {
case 'S': {
String s = (closure!=null? closure.p.source.toJavaString(): "=?");
info.put("source", new LString(s.replace('@','=')));
info.put("short_src", new LString(s.substring(1)));
info.put("linedefined", (closure!=null? closure.p.linedefined: 0));
info.put("lastlinedefined", (closure!=null? closure.p.lastlinedefined: 0));
info.put("what", new LString("Lua"));
if ( closure != null ) {
String s = closure.p.source.toJavaString();
info.put("what", new LString("Lua"));
info.put("source", new LString(s.replace('@','=')));
info.put("short_src", new LString(s.substring(1)));
info.put("linedefined", closure.p.linedefined);
info.put("lastlinedefined", closure.p.lastlinedefined);
} else {
info.put("what", new LString("Java"));
info.put("source", new LString("[Java]"));
info.put("short_src", new LString("[Java]"));
info.put("linedefined", -1);
}
break;
}
case 'l': {
@@ -242,8 +259,8 @@ public class DebugLib extends LFunction {
}
case 'n': {
// TODO: name
info.put("name", new LString("?"));
info.put("namewhat", new LString("?"));
info.put("name", (new LString(closure!=null? "?": func.toString())));
info.put("namewhat", new LString(""));
break;
}
case 'f': {
@@ -356,14 +373,25 @@ public class DebugLib extends LFunction {
}
}
private CallInfo getcallinfo(LuaState vm, LuaState threadVm, int level) {
--level ; // level 0 is the debug function itself
if ( level > threadVm.cc )
// return callinfo if level is a lua call, LFunction if a java call
private Object getcallinfoorfunction(LuaState vm, int level) {
if ( level < 0 )
return null;
if ( level < 0 )
level = 0;
int cc = threadVm.cc-level;
return threadVm.calls[cc];
for ( int i=vm.cc; i>=0; --i ) {
CallInfo ci = vm.calls[i];
int pc = ci.pc>0? ci.pc-1: 0;
int instr = ci.closure.p.code[pc];
if ( Lua.GET_OPCODE(instr) == Lua.OP_CALL ) {
LValue f = vm.stack[ci.base + Lua.GETARG_A(instr)];
if ( f.isFunction() && ! (f instanceof LClosure) ) {
if ( (level--) <= 0 )
return f;
}
}
if ( (level--) <= 0 )
return ci;
}
return null;
}
private void getmetatable(LuaState vm) {
@@ -452,9 +480,7 @@ public class DebugLib extends LFunction {
level = vm.optint(3,1);
if ( vm.gettop() >= 2 )
message = vm.tostring(2)+"\n";
String trace = threadVm.getStackTrace(level-1);
if ( trace.endsWith("\n") )
trace = trace.substring(0,trace.length()-1);
String trace = threadVm.getStackTrace(level);
vm.resettop();
vm.pushstring(message+trace);
}

View File

@@ -314,6 +314,7 @@ public class LuaState extends Lua {
* its original configuration. This is considered good programming practice.
*/
public void call( int nargs, int nreturns ) {
// save stack state
int oldbase = base;
try {
@@ -323,8 +324,15 @@ public class LuaState extends Lua {
// make or set up the call
this.nresults = nreturns;
if (this.stack[base].luaStackCall(this)) {
// call was set up on the stack,
if (this.stack[base].luaStackCall(this)) {
// call hook
if ( hooksenabled ) {
debugCallHooks( );
}
// call was set up on the stack,
// we still have to execute it
execute();
}
@@ -405,6 +413,12 @@ public class LuaState extends Lua {
// make or set up the call
this.nresults = nreturns;
if (this.stack[base].luaStackCall(this)) {
// call hook
if ( hooksenabled ) {
debugCallHooks( );
}
// call was set up on the stack,
// we still have to execute it
execute();
@@ -714,15 +728,17 @@ public class LuaState extends Lua {
// number of return values we need
c = LuaState.GETARG_C(i);
// call hook
if ( hooksenabled ) {
debugCallHooks( );
}
// make or set up the call
this.nresults = c - 1;
if (this.stack[base].luaStackCall(this))
if (this.stack[base].luaStackCall(this)) {
// call hook
if ( hooksenabled ) {
debugCallHooks( );
}
return;
}
// adjustTop only for case when call was completed
// and number of args > 0. If call completed but
@@ -733,6 +749,12 @@ public class LuaState extends Lua {
// restore base
base = ci.base;
// call hook
if ( hooksenabled ) {
debugReturnHooks( );
}
continue;
}
@@ -764,6 +786,12 @@ public class LuaState extends Lua {
// make or set up the call
try {
if (this.stack[base].luaStackCall(this)) {
// call hook
if ( hooksenabled ) {
debugCallHooks( );
}
return;
}
} catch (LuaErrorException e) {
@@ -1103,10 +1131,24 @@ public class LuaState extends Lua {
public String getStackTrace(int level) {
StringBuffer buffer = new StringBuffer();
for (int i = cc-level; i >= 0; i--) {
buffer.append(" ");
buffer.append(getFileLine(i));
buffer.append("\n");
String between = " ";
for (int i=cc; i>=0; --i) {
CallInfo ci = calls[i];
int pc = ci.pc>0? ci.pc-1: 0;
int instr = ci.closure.p.code[pc];
if ( Lua.GET_OPCODE(instr) == Lua.OP_CALL ) {
LValue f = stack[ci.base + Lua.GETARG_A(instr)];
if ( f.isFunction() && ! (f instanceof LClosure) ) {
if ( (level--) <= 0 ) {
buffer.append(between+"[Java]: in function "+f.toString());
between = "\n ";
}
}
}
if ( (level--) <= 0 ) {
buffer.append(between+getFileLine(i));
between = "\n ";
}
}
return buffer.toString();
}
@@ -2450,8 +2492,8 @@ public class LuaState extends Lua {
public int debugGetLineNumber(CallInfo ci) {
int[] li = ci.closure.p.lineinfo;
int pc = ci.pc - 1;
if ( li != null && pc >= 0 && pc < li.length )
int pc = ci.pc>0? ci.pc-1: 0;
if ( li != null && pc < li.length )
return li[pc];
return -1;
}