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

View File

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