From 4795171956419e6b7819943a1aa752fbf21dc2ab Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Fri, 14 Sep 2012 14:23:13 +0000 Subject: [PATCH] Improve debug support. --- src/core/org/luaj/vm2/Globals.java | 4 -- src/core/org/luaj/vm2/LuaClosure.java | 14 ++--- src/core/org/luaj/vm2/LuaFunction.java | 6 ++ src/core/org/luaj/vm2/LuaThread.java | 74 +++++++++++++--------- src/core/org/luaj/vm2/lib/BaseLib.java | 8 +-- src/core/org/luaj/vm2/lib/DebugLib.java | 84 ++++++++++++++++++++----- 6 files changed, 129 insertions(+), 61 deletions(-) diff --git a/src/core/org/luaj/vm2/Globals.java b/src/core/org/luaj/vm2/Globals.java index 9c96d6b2..1383fb07 100644 --- a/src/core/org/luaj/vm2/Globals.java +++ b/src/core/org/luaj/vm2/Globals.java @@ -28,8 +28,6 @@ import org.luaj.vm2.LoadState.LuaCompiler; import org.luaj.vm2.lib.BaseLib; import org.luaj.vm2.lib.DebugLib; 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. @@ -65,8 +63,6 @@ public class Globals extends LuaTable { public LuaCompiler compiler = null; - public LuaThread.CallStack callstack = new LuaThread.CallStack(); - public BaseLib baselib; public LuaValue errorfunc; diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index e4541782..c4481e06 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -188,14 +188,14 @@ public class LuaClosure extends LuaFunction { UpValue[] openups = p.p.length>0? new UpValue[p.p.length]: null; // debug wants args to this function - if (globals != null) - globals.callstack.onCall( this, varargs, stack ); + if (DebugLib.DEBUG_ENABLED && globals != null) + globals.running_thread.callstack.onCall( this, varargs, stack ); // process instructions try { while ( true ) { if (DebugLib.DEBUG_ENABLED && globals != null) - globals.callstack.onInstruction( pc, v, top ); + globals.running_thread.callstack.onInstruction( pc, v, top ); // pull out instruction i = code[pc++]; @@ -502,8 +502,8 @@ public class LuaClosure extends LuaFunction { processErrorHooks(le, p, pc); throw le; } finally { - if (globals != null) - globals.callstack.onReturn(); + if (DebugLib.DEBUG_ENABLED && globals != null) + globals.running_thread.callstack.onReturn(); if ( openups != null ) for ( int u=openups.length; --u>=0; ) 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]): "?"); le.traceback = errorHook(le.getMessage()); 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) { @@ -567,7 +567,7 @@ public class LuaClosure extends LuaFunction { String msg = e.getMessage(); if ( msg == null ) return null; 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; LuaClosure c = (LuaClosure) f; LuaString file = c.p.source != null ? c.p.source: valueOf("?"); diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/src/core/org/luaj/vm2/LuaFunction.java index 7138d52f..c5b48d33 100644 --- a/src/core/org/luaj/vm2/LuaFunction.java +++ b/src/core/org/luaj/vm2/LuaFunction.java @@ -69,4 +69,10 @@ public class LuaFunction extends LuaValue { */ public void initupvalue1(LuaValue env) { } + + public String tojstring() { + String s = getClass().getName(); + return "function: " + s.substring(s.lastIndexOf('.')+1); + } + } diff --git a/src/core/org/luaj/vm2/LuaThread.java b/src/core/org/luaj/vm2/LuaThread.java index d66c6db2..59ace7fd 100644 --- a/src/core/org/luaj/vm2/LuaThread.java +++ b/src/core/org/luaj/vm2/LuaThread.java @@ -24,7 +24,6 @@ package org.luaj.vm2; import java.lang.ref.WeakReference; -import org.luaj.vm2.LuaThread.CallFrame; import org.luaj.vm2.lib.DebugLib; /** @@ -85,7 +84,7 @@ public class LuaThread extends LuaValue { public final State state; - final CallStack callstack = new CallStack(); + public final CallStack callstack = new CallStack(); public static final int MAX_CALLSTACK = 256; @@ -360,38 +359,51 @@ public class LuaThread extends LuaValue { if (DebugLib.DEBUG_ENABLED && DebugLib.TRACE & f.isclosure()) 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) { - if (!f.isclosure()) - return NONE; - LuaClosure c = (LuaClosure) f; - Prototype p = c.p; - if (i < 1 || i > stack.length) - 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; + LuaString name = getlocalname(i); + if ( name != null ) + return varargsOf( name, stack[i-1] ); + else + return NIL; } public Varargs setLocal(int i, LuaValue value) { - if (!f.isclosure()) - return NONE; - LuaClosure c = (LuaClosure) f; - Prototype p = c.p; - if (i < 1 || i > stack.length) - return NONE; - stack[i] = value; - if (p.locvars != null && p.locvars.length >= i) - return p.locvars[i-1].varname; - return NONE; + LuaString name = getlocalname(i); + if ( name != null ) { + stack[i-1] = value; + return name; + } else { + return NIL; + } + } + public int currentline() { + 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(); } } diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index cb2a9ee9..559a6e3e 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -208,11 +208,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { final class pcall extends VarArgFunction { public Varargs invoke(Varargs args) { LuaValue func = args.checkvalue(1); - globals.callstack.onCall(this); + globals.running_thread.callstack.onCall(this); try { return pcall(func,args.subargs(2),null); } finally { - globals.callstack.onReturn(); + globals.running_thread.callstack.onReturn(); } } } @@ -350,11 +350,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { // "xpcall", // (f, err) -> result1, ... final class xpcall extends VarArgFunction { public Varargs invoke(Varargs args) { - globals.callstack.onCall(this); + globals.running_thread.callstack.onCall(this); try { return pcall(args.arg1(),NONE,args.checkvalue(2)); } finally { - globals.callstack.onReturn(); + globals.running_thread.callstack.onReturn(); } } } diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index aaaf52a0..084296e8 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -153,7 +153,7 @@ public class DebugLib extends OneArgFunction { LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; LuaValue func = args.optfunction(a++, null); 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 local = 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; String message = args.optjstring(a++, null); 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); } } @@ -339,7 +339,7 @@ public class DebugLib extends OneArgFunction { LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running_thread; LuaValue func = args.arg(a++); String what = args.optjstring(a++, "nSluf"); - LuaThread.CallStack callstack = thread.globals.callstack; + LuaThread.CallStack callstack = thread.callstack; // find the stack info LuaThread.CallFrame frame; @@ -376,7 +376,7 @@ public class DebugLib extends OneArgFunction { break; } case 'l': { - int line = frame.getLine(); + int line = frame.currentline(); info.set( CURRENTLINE, valueOf(line) ); break; } @@ -385,7 +385,7 @@ public class DebugLib extends OneArgFunction { break; } case 'n': { - LuaString[] kind = getfunckind(frame.f); + LuaString[] kind = frame.getfunckind(); info.set(NAME, kind!=null? kind[0]: QMARK); info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING); break; @@ -394,18 +394,14 @@ public class DebugLib extends OneArgFunction { info.set( FUNC, frame.f ); break; } - /* case 'L': { LuaTable lines = new LuaTable(); info.set(ACTIVELINES, lines); - if ( c !+ null && c.luainfo != null ) { - int line = c.luainfo.currentline(); - if ( line >= 0 ) - lines.set(1, IntValue.valueOf(line)); - } + int line = frame.currentline(); + if ( line >= 0 ) + lines.set(1, valueOf(line)); break; } - */ } } return info; @@ -427,10 +423,68 @@ public class DebugLib extends OneArgFunction { if (!x) throw new RuntimeException("lua_assert failed"); } - private LuaString[] getfunckind(LuaFunction f) { - return null; + // return StrValue[] { name, namewhat } if found, null if not + 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'