Improve call hooks, stack trace and getinfo reporting.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user