Improve debug support.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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("?");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
Reference in New Issue
Block a user