Improve debug support.

This commit is contained in:
James Roseborough
2012-09-14 14:23:13 +00:00
parent f786802bf1
commit 4795171956
6 changed files with 129 additions and 61 deletions

View File

@@ -28,8 +28,6 @@ import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.lib.BaseLib; import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.DebugLib; import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.ResourceFinder; import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Global environment used by luaj. * Global environment used by luaj.
@@ -65,8 +63,6 @@ public class Globals extends LuaTable {
public LuaCompiler compiler = null; public LuaCompiler compiler = null;
public LuaThread.CallStack callstack = new LuaThread.CallStack();
public BaseLib baselib; public BaseLib baselib;
public LuaValue errorfunc; public LuaValue errorfunc;

View File

@@ -188,14 +188,14 @@ public class LuaClosure extends LuaFunction {
UpValue[] openups = p.p.length>0? new UpValue[p.p.length]: null; UpValue[] openups = p.p.length>0? new UpValue[p.p.length]: null;
// debug wants args to this function // debug wants args to this function
if (globals != null) if (DebugLib.DEBUG_ENABLED && globals != null)
globals.callstack.onCall( this, varargs, stack ); globals.running_thread.callstack.onCall( this, varargs, stack );
// process instructions // process instructions
try { try {
while ( true ) { while ( true ) {
if (DebugLib.DEBUG_ENABLED && globals != null) if (DebugLib.DEBUG_ENABLED && globals != null)
globals.callstack.onInstruction( pc, v, top ); globals.running_thread.callstack.onInstruction( pc, v, top );
// pull out instruction // pull out instruction
i = code[pc++]; i = code[pc++];
@@ -502,8 +502,8 @@ public class LuaClosure extends LuaFunction {
processErrorHooks(le, p, pc); processErrorHooks(le, p, pc);
throw le; throw le;
} finally { } finally {
if (globals != null) if (DebugLib.DEBUG_ENABLED && globals != null)
globals.callstack.onReturn(); globals.running_thread.callstack.onReturn();
if ( openups != null ) if ( openups != null )
for ( int u=openups.length; --u>=0; ) for ( int u=openups.length; --u>=0; )
if ( openups[u] != null ) if ( openups[u] != null )
@@ -534,7 +534,7 @@ public class LuaClosure extends LuaFunction {
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?"); + (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?");
le.traceback = errorHook(le.getMessage()); le.traceback = errorHook(le.getMessage());
if (DebugLib.DEBUG_ENABLED && globals != null && globals.debuglib != null) if (DebugLib.DEBUG_ENABLED && globals != null && globals.debuglib != null)
le.traceback += globals.callstack.traceback(le.level); le.traceback += globals.running_thread.callstack.traceback(le.level);
} }
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) { private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
@@ -567,7 +567,7 @@ public class LuaClosure extends LuaFunction {
String msg = e.getMessage(); String msg = e.getMessage();
if ( msg == null ) return null; if ( msg == null ) return null;
if ( globals == null ) return msg; if ( globals == null ) return msg;
LuaFunction f = globals.callstack.getFunction(1); LuaFunction f = globals.running_thread.callstack.getFunction(1);
if ( ! (f instanceof LuaClosure) ) return msg; if ( ! (f instanceof LuaClosure) ) return msg;
LuaClosure c = (LuaClosure) f; LuaClosure c = (LuaClosure) f;
LuaString file = c.p.source != null ? c.p.source: valueOf("?"); LuaString file = c.p.source != null ? c.p.source: valueOf("?");

View File

@@ -69,4 +69,10 @@ public class LuaFunction extends LuaValue {
*/ */
public void initupvalue1(LuaValue env) { public void initupvalue1(LuaValue env) {
} }
public String tojstring() {
String s = getClass().getName();
return "function: " + s.substring(s.lastIndexOf('.')+1);
}
} }

View File

@@ -24,7 +24,6 @@ package org.luaj.vm2;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import org.luaj.vm2.LuaThread.CallFrame;
import org.luaj.vm2.lib.DebugLib; import org.luaj.vm2.lib.DebugLib;
/** /**
@@ -85,7 +84,7 @@ public class LuaThread extends LuaValue {
public final State state; public final State state;
final CallStack callstack = new CallStack(); public final CallStack callstack = new CallStack();
public static final int MAX_CALLSTACK = 256; public static final int MAX_CALLSTACK = 256;
@@ -360,38 +359,51 @@ public class LuaThread extends LuaValue {
if (DebugLib.DEBUG_ENABLED && DebugLib.TRACE & f.isclosure()) if (DebugLib.DEBUG_ENABLED && DebugLib.TRACE & f.isclosure())
Print.printState(f.checkclosure(), pc, stack, top, v); Print.printState(f.checkclosure(), pc, stack, top, v);
} }
public int getLine() {
if (!f.isclosure())
return 0;
LuaClosure c = (LuaClosure) f;
Prototype p = c.p;
if (p.lineinfo == null || pc < 0 || pc >= p.lineinfo[pc])
return 0;
return p.lineinfo[pc];
}
public Varargs getLocal(int i) { public Varargs getLocal(int i) {
if (!f.isclosure()) LuaString name = getlocalname(i);
return NONE; if ( name != null )
LuaClosure c = (LuaClosure) f; return varargsOf( name, stack[i-1] );
Prototype p = c.p; else
if (i < 1 || i > stack.length) return NIL;
if (p.locvars != null && p.locvars.length >= i)
return varargsOf(stack[i-1], p.locvars[i-1].varname);
else
return stack[i-1];
return NONE;
} }
public Varargs setLocal(int i, LuaValue value) { public Varargs setLocal(int i, LuaValue value) {
if (!f.isclosure()) LuaString name = getlocalname(i);
return NONE; if ( name != null ) {
LuaClosure c = (LuaClosure) f; stack[i-1] = value;
Prototype p = c.p; return name;
if (i < 1 || i > stack.length) } else {
return NONE; return NIL;
stack[i] = value; }
if (p.locvars != null && p.locvars.length >= i) }
return p.locvars[i-1].varname; public int currentline() {
return NONE; if ( !f.isclosure() ) return -1;
int[] li = ((LuaClosure)f).p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc];
}
public LuaString[] getfunckind() {
if ( !f.isclosure() || pc<0 ) return null;
Prototype p = ((LuaClosure)f).p;
int stackpos = (p.code[pc] >> 6) & 0xff;
return DebugLib.getobjname(p, pc, stackpos);
}
public String sourceline() {
if ( !f.isclosure() ) return f.tojstring();
String s = ((LuaClosure)f).p.source.tojstring();
int line = currentline();
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
}
public String tracename() {
LuaString[] kind = getfunckind();
if ( kind == null )
return "function ?";
return "function "+kind[0].tojstring();
}
public LuaString getlocalname(int index) {
if ( !f.isclosure() ) return null;
return ((LuaClosure)f).p.getlocalname(index, pc);
}
public String tojstring() {
return tracename()+" "+sourceline();
} }
} }

View File

@@ -208,11 +208,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
final class pcall extends VarArgFunction { final class pcall extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1); LuaValue func = args.checkvalue(1);
globals.callstack.onCall(this); globals.running_thread.callstack.onCall(this);
try { try {
return pcall(func,args.subargs(2),null); return pcall(func,args.subargs(2),null);
} finally { } finally {
globals.callstack.onReturn(); globals.running_thread.callstack.onReturn();
} }
} }
} }
@@ -350,11 +350,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder {
// "xpcall", // (f, err) -> result1, ... // "xpcall", // (f, err) -> result1, ...
final class xpcall extends VarArgFunction { final class xpcall extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
globals.callstack.onCall(this); globals.running_thread.callstack.onCall(this);
try { try {
return pcall(args.arg1(),NONE,args.checkvalue(2)); return pcall(args.arg1(),NONE,args.checkvalue(2));
} finally { } finally {
globals.callstack.onReturn(); globals.running_thread.callstack.onReturn();
} }
} }
} }

View File

@@ -153,7 +153,7 @@ public class DebugLib extends OneArgFunction {
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.optfunction(a++, null); LuaValue func = args.optfunction(a++, null);
LuaValue local = args.checkvalue(a++); LuaValue local = args.checkvalue(a++);
return thread.globals.callstack.findCallFrame(func).getLocal(local.toint()); return thread.callstack.findCallFrame(func).getLocal(local.toint());
} }
} }
@@ -228,7 +228,7 @@ public class DebugLib extends OneArgFunction {
LuaValue func = args.optfunction(a++, null); LuaValue func = args.optfunction(a++, null);
LuaValue local = args.checkvalue(a++); LuaValue local = args.checkvalue(a++);
LuaValue value = args.checkvalue(a++); LuaValue value = args.checkvalue(a++);
return thread.globals.callstack.findCallFrame(func).setLocal(local.toint(), value); return thread.callstack.findCallFrame(func).setLocal(local.toint(), value);
} }
} }
@@ -291,7 +291,7 @@ public class DebugLib extends OneArgFunction {
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
String message = args.optjstring(a++, null); String message = args.optjstring(a++, null);
int level = args.optint(a++,1); int level = args.optint(a++,1);
String tb = globals.callstack.traceback(level-1); String tb = thread.callstack.traceback(level-1);
return valueOf(message!=null? message+"\n"+tb: tb); return valueOf(message!=null? message+"\n"+tb: tb);
} }
} }
@@ -339,7 +339,7 @@ public class DebugLib extends OneArgFunction {
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread;
LuaValue func = args.arg(a++); LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "nSluf"); String what = args.optjstring(a++, "nSluf");
LuaThread.CallStack callstack = thread.globals.callstack; LuaThread.CallStack callstack = thread.callstack;
// find the stack info // find the stack info
LuaThread.CallFrame frame; LuaThread.CallFrame frame;
@@ -376,7 +376,7 @@ public class DebugLib extends OneArgFunction {
break; break;
} }
case 'l': { case 'l': {
int line = frame.getLine(); int line = frame.currentline();
info.set( CURRENTLINE, valueOf(line) ); info.set( CURRENTLINE, valueOf(line) );
break; break;
} }
@@ -385,7 +385,7 @@ public class DebugLib extends OneArgFunction {
break; break;
} }
case 'n': { case 'n': {
LuaString[] kind = getfunckind(frame.f); LuaString[] kind = frame.getfunckind();
info.set(NAME, kind!=null? kind[0]: QMARK); info.set(NAME, kind!=null? kind[0]: QMARK);
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING); info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
break; break;
@@ -394,18 +394,14 @@ public class DebugLib extends OneArgFunction {
info.set( FUNC, frame.f ); info.set( FUNC, frame.f );
break; break;
} }
/*
case 'L': { case 'L': {
LuaTable lines = new LuaTable(); LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines); info.set(ACTIVELINES, lines);
if ( c !+ null && c.luainfo != null ) { int line = frame.currentline();
int line = c.luainfo.currentline(); if ( line >= 0 )
if ( line >= 0 ) lines.set(1, valueOf(line));
lines.set(1, IntValue.valueOf(line));
}
break; break;
} }
*/
} }
} }
return info; return info;
@@ -427,10 +423,68 @@ public class DebugLib extends OneArgFunction {
if (!x) throw new RuntimeException("lua_assert failed"); if (!x) throw new RuntimeException("lua_assert failed");
} }
private LuaString[] getfunckind(LuaFunction f) { // return StrValue[] { name, namewhat } if found, null if not
return null; public static LuaString[] getobjname(Prototype p, int lastpc, int reg) {
int pc = lastpc; // currentpc(L, ci);
LuaString name = p.getlocalname(reg + 1, pc);
if (name != null) /* is a local? */
return new LuaString[] { name, LOCAL };
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
int i = p.code[pc];
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_MOVE: {
int a = Lua.GETARG_A(i);
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
if (b < a)
return getobjname(p, pc, b); /* get name for `b' */
break;
}
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_Bx(i); /* table index */
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k);
return new LuaString[] { name, vn.eq_b(ENV)? GLOBAL: FIELD };
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return new LuaString[] { name, UPVALUE };
}
case Lua.OP_LOADK:
case Lua.OP_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
: Lua.GETARG_Ax(p.code[pc + 1]);
if (p.k[b].isstring()) {
name = p.k[b].strvalue();
return new LuaString[] { name, CONSTANT };
}
break;
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new LuaString[] { name, METHOD };
}
default:
break;
}
}
return null; /* no useful name found */
} }
static LuaString kname(Prototype p, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
return p.k[Lua.INDEXK(c)].strvalue();
else
return QMARK;
}
/* /*
** try to find last instruction before 'lastpc' that modified register 'reg' ** try to find last instruction before 'lastpc' that modified register 'reg'