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.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 )
|
|
||||||
return null;
|
|
||||||
if ( level < 0 )
|
if ( level < 0 )
|
||||||
level = 0;
|
return null;
|
||||||
int cc = threadVm.cc-level;
|
for ( int i=vm.cc; i>=0; --i ) {
|
||||||
return threadVm.calls[cc];
|
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) {
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)) {
|
if (this.stack[base].luaStackCall(this)) {
|
||||||
// call was set up on the stack,
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user