Improve debug lib consistency with lua 5.2
This commit is contained in:
@@ -192,15 +192,15 @@ public class LuaClosure extends LuaFunction {
|
|||||||
// TODO: use linked list.
|
// TODO: use linked list.
|
||||||
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
|
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
|
||||||
|
|
||||||
// debug wants args to this function
|
// allow for debug hooks
|
||||||
if (DebugLib.DEBUG_ENABLED && globals != null)
|
if (globals != null && globals.debuglib != null)
|
||||||
globals.running_thread.callstack.onCall( this, varargs, stack );
|
globals.debuglib.onCall( this, varargs, stack );
|
||||||
|
|
||||||
// process instructions
|
// process instructions
|
||||||
try {
|
try {
|
||||||
while ( true ) {
|
while ( true ) {
|
||||||
if (DebugLib.DEBUG_ENABLED && globals != null)
|
if (globals != null && globals.debuglib != null)
|
||||||
globals.running_thread.callstack.onInstruction( pc, v, top );
|
globals.debuglib.onInstruction( pc, v, top );
|
||||||
|
|
||||||
// pull out instruction
|
// pull out instruction
|
||||||
i = code[pc++];
|
i = code[pc++];
|
||||||
@@ -507,12 +507,12 @@ public class LuaClosure extends LuaFunction {
|
|||||||
processErrorHooks(le, p, pc);
|
processErrorHooks(le, p, pc);
|
||||||
throw le;
|
throw le;
|
||||||
} finally {
|
} finally {
|
||||||
if (DebugLib.DEBUG_ENABLED && globals != null)
|
|
||||||
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 )
|
||||||
openups[u].close();
|
openups[u].close();
|
||||||
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,8 +538,8 @@ public class LuaClosure extends LuaFunction {
|
|||||||
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
|
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
|
||||||
+ (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 (globals != null && globals.debuglib != null)
|
||||||
le.traceback += globals.running_thread.callstack.traceback(le.level);
|
le.traceback += globals.debuglib.traceback(le.level);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
|
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
|
||||||
@@ -562,21 +562,4 @@ public class LuaClosure extends LuaFunction {
|
|||||||
upValues[i].setValue(v);
|
upValues[i].setValue(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add file and line info to a message at a particular level
|
|
||||||
* @param message the String message to use
|
|
||||||
* @param level where to supply line info from in call stack
|
|
||||||
* */
|
|
||||||
private String getFileLineMessage( Exception e, int pc ) {
|
|
||||||
String msg = e.getMessage();
|
|
||||||
if ( msg == null ) return null;
|
|
||||||
if ( globals == null ) return msg;
|
|
||||||
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("?");
|
|
||||||
String line = c.p.lineinfo != null && pc < c.p.lineinfo.length? String.valueOf(c.p.lineinfo[pc]): "?";
|
|
||||||
return file.tojstring() + ": " + line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class LuaError extends RuntimeException {
|
|||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return traceback != null? traceback:
|
return traceback != null? traceback:
|
||||||
(fileline != null? fileline: "?:-1") + " " + super.getMessage();
|
(fileline != null? fileline + " ": "") + super.getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct LuaError when a program exception occurs.
|
/** Construct LuaError when a program exception occurs.
|
||||||
|
|||||||
@@ -84,21 +84,14 @@ public class LuaThread extends LuaValue {
|
|||||||
|
|
||||||
public final State state;
|
public final State state;
|
||||||
|
|
||||||
public final CallStack callstack = new CallStack();
|
|
||||||
|
|
||||||
public static final int MAX_CALLSTACK = 256;
|
public static final int MAX_CALLSTACK = 256;
|
||||||
|
|
||||||
/** Interval to check for LuaThread dereferencing. */
|
/** Interval to check for LuaThread dereferencing. */
|
||||||
public static int GC_INTERVAL = 30000;
|
public static int GC_INTERVAL = 30000;
|
||||||
|
|
||||||
/** Thread-local used by DebugLib to store debugging state. */
|
/** Thread-local used by DebugLib to store debugging state.
|
||||||
public Object debugState;
|
* This is ano opaque value that should not be modified by applications. */
|
||||||
|
public Object callstack;
|
||||||
public LuaValue hookfunc;
|
|
||||||
public boolean hookline;
|
|
||||||
public boolean hookcall;
|
|
||||||
public boolean hookrtrn;
|
|
||||||
public int hookcount;
|
|
||||||
|
|
||||||
public final Globals globals;
|
public final Globals globals;
|
||||||
|
|
||||||
@@ -239,179 +232,5 @@ public class LuaThread extends LuaValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CallStack {
|
|
||||||
final CallFrame[] frame = new CallFrame[MAX_CALLSTACK];
|
|
||||||
int calls = 0;
|
|
||||||
|
|
||||||
CallStack() {
|
|
||||||
for (int i = 0; i < MAX_CALLSTACK; ++i)
|
|
||||||
frame[i] = new CallFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to indicate the start of a call
|
|
||||||
* @param stack
|
|
||||||
* @param varargs
|
|
||||||
* @see DebugLib
|
|
||||||
*/
|
|
||||||
public final void onCall(LuaFunction function) {
|
|
||||||
frame[calls++].set(function);
|
|
||||||
// if (DebugLib.DEBUG_ENABLED)
|
|
||||||
// DebugLib.debugOnCall(globals.running_thread, calls, function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void onCall(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
|
||||||
frame[calls++].set(function, varargs, stack);
|
|
||||||
// if (DebugLib.DEBUG_ENABLED)
|
|
||||||
// DebugLib.debugOnCall(globals.running_thread, calls, function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to signal the end of a call
|
|
||||||
* @see DebugLib
|
|
||||||
*/
|
|
||||||
public final void onReturn() {
|
|
||||||
frame[--calls].reset();
|
|
||||||
// if (DebugLib.DEBUG_ENABLED)
|
|
||||||
// DebugLib.debugOnReturn(running_thread, calls);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void onInstruction(int pc, Varargs v, int top) {
|
|
||||||
frame[calls-1].instr(pc, v, top);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get number of calls in stack
|
|
||||||
* @return number of calls in current call stack
|
|
||||||
* @see DebugLib
|
|
||||||
*/
|
|
||||||
public final int getCallstackDepth() {
|
|
||||||
return calls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the function at a particular level of the stack.
|
|
||||||
* @param level # of levels back from the top of the stack.
|
|
||||||
* @return LuaFunction, or null if beyond the stack limits.
|
|
||||||
*/
|
|
||||||
public LuaFunction getFunction(int level) {
|
|
||||||
return level>0 && level<=calls? frame[calls-level].f: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the traceback starting at a specific level.
|
|
||||||
* @param level
|
|
||||||
* @return String containing the traceback.
|
|
||||||
*/
|
|
||||||
public String traceback(int level) {
|
|
||||||
StringBuffer sb = new StringBuffer();
|
|
||||||
sb.append( "stack traceback:" );
|
|
||||||
CallFrame c = getCallFrame(level);
|
|
||||||
if (c != null) {
|
|
||||||
sb.append("\n\t");
|
|
||||||
sb.append( c.sourceline() );
|
|
||||||
sb.append( " in " );
|
|
||||||
while ( (c = getCallFrame(++level)) != null ) {
|
|
||||||
sb.append( c.tracename() );
|
|
||||||
sb.append( "\n\t" );
|
|
||||||
sb.append( c.sourceline() );
|
|
||||||
sb.append( " in " );
|
|
||||||
}
|
|
||||||
sb.append( "main chunk" );
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CallFrame getCallFrame(int level) {
|
|
||||||
if (level < 1 || level >= calls)
|
|
||||||
return null;
|
|
||||||
return frame[calls-level];
|
|
||||||
}
|
|
||||||
|
|
||||||
public CallFrame findCallFrame(LuaValue func) {
|
|
||||||
for (int i = 1; i <= calls; ++i)
|
|
||||||
if (frame[calls-i].f == func)
|
|
||||||
return frame[i];
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CallFrame {
|
|
||||||
public LuaFunction f;
|
|
||||||
public int pc;
|
|
||||||
int top;
|
|
||||||
Varargs v;
|
|
||||||
LuaValue[] stack;
|
|
||||||
boolean tail;
|
|
||||||
public void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
|
||||||
this.f = function;
|
|
||||||
this.v = varargs;
|
|
||||||
this.stack = stack;
|
|
||||||
this.tail = false;
|
|
||||||
}
|
|
||||||
public void set(LuaFunction function) {
|
|
||||||
this.f = function;
|
|
||||||
}
|
|
||||||
public void reset() {
|
|
||||||
this.f = null;
|
|
||||||
this.v = null;
|
|
||||||
this.stack = null;
|
|
||||||
}
|
|
||||||
public void instr(int pc, Varargs v, int top) {
|
|
||||||
this.pc = pc;
|
|
||||||
this.v = v;
|
|
||||||
this.top = top;
|
|
||||||
if (f.checkclosure().p.code[pc] == Lua.OP_TAILCALL)
|
|
||||||
this.tail = true;
|
|
||||||
if (DebugLib.TRACE)
|
|
||||||
Print.printState(f.checkclosure(), pc, stack, top, v);
|
|
||||||
}
|
|
||||||
public Varargs getLocal(int i) {
|
|
||||||
LuaString name = getlocalname(i);
|
|
||||||
if ( name != null )
|
|
||||||
return varargsOf( name, stack[i-1] );
|
|
||||||
else
|
|
||||||
return NIL;
|
|
||||||
}
|
|
||||||
public Varargs setLocal(int i, LuaValue value) {
|
|
||||||
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 = f.checkclosure().p.lineinfo;
|
|
||||||
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
|
||||||
}
|
|
||||||
public String sourceline() {
|
|
||||||
if ( !f.isclosure() ) return f.tojstring();
|
|
||||||
String s = f.checkclosure().p.source.tojstring();
|
|
||||||
int line = currentline();
|
|
||||||
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
|
|
||||||
}
|
|
||||||
public String tracename() {
|
|
||||||
LuaString[] kind = DebugLib.getfuncname(this);
|
|
||||||
if ( kind == null )
|
|
||||||
return "function ?";
|
|
||||||
return "function "+kind[0].tojstring();
|
|
||||||
}
|
|
||||||
public LuaString getlocalname(int index) {
|
|
||||||
if ( !f.isclosure() ) return null;
|
|
||||||
return f.checkclosure().p.getlocalname(index, pc);
|
|
||||||
}
|
|
||||||
public String tojstring() {
|
|
||||||
return tracename()+" "+sourceline();
|
|
||||||
}
|
|
||||||
public boolean istailcall() {
|
|
||||||
return tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,11 +208,13 @@ 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.running_thread.callstack.onCall(this);
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onCall(this);
|
||||||
try {
|
try {
|
||||||
return pcall(func,args.subargs(2),null);
|
return pcall(func,args.subargs(2),null);
|
||||||
} finally {
|
} finally {
|
||||||
globals.running_thread.callstack.onReturn();
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,11 +352,13 @@ 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.running_thread.callstack.onCall(this);
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onCall(this);
|
||||||
try {
|
try {
|
||||||
return pcall(args.arg1(),NONE,args.checkvalue(2));
|
return pcall(args.arg1(),args.subargs(3),args.checkvalue(2));
|
||||||
} finally {
|
} finally {
|
||||||
globals.running_thread.callstack.onReturn();
|
if (globals != null && globals.debuglib != null)
|
||||||
|
globals.debuglib.onReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,21 +26,17 @@ import org.luaj.vm2.LoadState.LuaCompiler;
|
|||||||
import org.luaj.vm2.Lua;
|
import org.luaj.vm2.Lua;
|
||||||
import org.luaj.vm2.LuaBoolean;
|
import org.luaj.vm2.LuaBoolean;
|
||||||
import org.luaj.vm2.LuaClosure;
|
import org.luaj.vm2.LuaClosure;
|
||||||
import org.luaj.vm2.LuaError;
|
|
||||||
import org.luaj.vm2.LuaFunction;
|
import org.luaj.vm2.LuaFunction;
|
||||||
import org.luaj.vm2.LuaNil;
|
import org.luaj.vm2.LuaNil;
|
||||||
import org.luaj.vm2.LuaNumber;
|
import org.luaj.vm2.LuaNumber;
|
||||||
import org.luaj.vm2.LuaString;
|
import org.luaj.vm2.LuaString;
|
||||||
import org.luaj.vm2.LuaTable;
|
import org.luaj.vm2.LuaTable;
|
||||||
import org.luaj.vm2.LuaThread;
|
import org.luaj.vm2.LuaThread;
|
||||||
import org.luaj.vm2.LuaThread.CallFrame;
|
|
||||||
import org.luaj.vm2.LuaUserdata;
|
import org.luaj.vm2.LuaUserdata;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
|
import org.luaj.vm2.Print;
|
||||||
import org.luaj.vm2.Prototype;
|
import org.luaj.vm2.Prototype;
|
||||||
import org.luaj.vm2.Varargs;
|
import org.luaj.vm2.Varargs;
|
||||||
import org.luaj.vm2.lib.jme.JmePlatform;
|
|
||||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
|
||||||
import org.luaj.vm2.luajc.LuaJC;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
|
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
|
||||||
@@ -73,10 +69,6 @@ import org.luaj.vm2.luajc.LuaJC;
|
|||||||
public class DebugLib extends OneArgFunction {
|
public class DebugLib extends OneArgFunction {
|
||||||
public static final boolean CALLS = (null != System.getProperty("CALLS"));
|
public static final boolean CALLS = (null != System.getProperty("CALLS"));
|
||||||
public static final boolean TRACE = (null != System.getProperty("TRACE"));
|
public static final boolean TRACE = (null != System.getProperty("TRACE"));
|
||||||
|
|
||||||
// leave this unset to allow obfuscators to
|
|
||||||
// remove it in production builds
|
|
||||||
public static boolean DEBUG_ENABLED;
|
|
||||||
|
|
||||||
private static final LuaString LUA = valueOf("Lua");
|
private static final LuaString LUA = valueOf("Lua");
|
||||||
private static final LuaString JAVA = valueOf("Java");
|
private static final LuaString JAVA = valueOf("Java");
|
||||||
@@ -89,8 +81,7 @@ public class DebugLib extends OneArgFunction {
|
|||||||
private static final LuaString CALL = valueOf("call");
|
private static final LuaString CALL = valueOf("call");
|
||||||
private static final LuaString LINE = valueOf("line");
|
private static final LuaString LINE = valueOf("line");
|
||||||
private static final LuaString COUNT = valueOf("count");
|
private static final LuaString COUNT = valueOf("count");
|
||||||
private static final LuaString RETURN = valueOf("return");
|
private static final LuaString RETURN = valueOf("return");
|
||||||
private static final LuaString TAILRETURN = valueOf("tail return");
|
|
||||||
private static final LuaString CONSTANT = valueOf("constant");
|
private static final LuaString CONSTANT = valueOf("constant");
|
||||||
private static final LuaString FOR_ITERATOR = valueOf("for iterator");
|
private static final LuaString FOR_ITERATOR = valueOf("for iterator");
|
||||||
private static final LuaString METAMETHOD = valueOf("metamethod");
|
private static final LuaString METAMETHOD = valueOf("metamethod");
|
||||||
@@ -112,10 +103,18 @@ public class DebugLib extends OneArgFunction {
|
|||||||
|
|
||||||
Globals globals;
|
Globals globals;
|
||||||
|
|
||||||
|
LuaValue hookfunc;
|
||||||
|
boolean hookline;
|
||||||
|
boolean hookcall;
|
||||||
|
boolean hookrtrn;
|
||||||
|
int hookcount;
|
||||||
|
boolean inhook;
|
||||||
|
int lastline;
|
||||||
|
int bytecodes;
|
||||||
|
|
||||||
public LuaTable call(LuaValue env) {
|
public LuaTable call(LuaValue env) {
|
||||||
globals = env.checkglobals();
|
globals = env.checkglobals();
|
||||||
globals.debuglib = this;
|
globals.debuglib = this;
|
||||||
DEBUG_ENABLED = true;
|
|
||||||
LuaTable debug = new LuaTable();
|
LuaTable debug = new LuaTable();
|
||||||
debug.set("debug", new debug());
|
debug.set("debug", new debug());
|
||||||
debug.set("gethook", new gethook());
|
debug.set("gethook", new gethook());
|
||||||
@@ -148,11 +147,10 @@ public class DebugLib extends OneArgFunction {
|
|||||||
// debug.gethook ([thread])
|
// debug.gethook ([thread])
|
||||||
final class gethook extends VarArgFunction {
|
final class gethook extends VarArgFunction {
|
||||||
public Varargs invoke(Varargs args) {
|
public Varargs invoke(Varargs args) {
|
||||||
LuaThread t = args.optthread(1, globals.running_thread);
|
|
||||||
return varargsOf(
|
return varargsOf(
|
||||||
t.hookfunc,
|
hookfunc,
|
||||||
valueOf((t.hookcall?"c":"")+(t.hookline?"l":"")+(t.hookrtrn?"r":"")),
|
valueOf((hookcall?"c":"")+(hookline?"l":"")+(hookrtrn?"r":"")),
|
||||||
valueOf(t.hookcount));
|
valueOf(hookcount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +161,10 @@ 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++, "flnStu");
|
String what = args.optjstring(a++, "flnStu");
|
||||||
LuaThread.CallStack callstack = thread.callstack;
|
DebugLib.CallStack callstack = callstack(thread);
|
||||||
|
|
||||||
// find the stack info
|
// find the stack info
|
||||||
LuaThread.CallFrame frame;
|
DebugLib.CallFrame frame;
|
||||||
if ( func.isnumber() ) {
|
if ( func.isnumber() ) {
|
||||||
frame = callstack.getCallFrame(func.toint());
|
frame = callstack.getCallFrame(func.toint());
|
||||||
if (frame == null)
|
if (frame == null)
|
||||||
@@ -220,7 +218,7 @@ public class DebugLib extends OneArgFunction {
|
|||||||
if (what.indexOf('L') >= 0) {
|
if (what.indexOf('L') >= 0) {
|
||||||
LuaTable lines = new LuaTable();
|
LuaTable lines = new LuaTable();
|
||||||
info.set(ACTIVELINES, lines);
|
info.set(ACTIVELINES, lines);
|
||||||
CallFrame cf;
|
DebugLib.CallFrame cf;
|
||||||
for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
|
for (int l = 1; (cf=callstack.getCallFrame(l)) != null; ++l)
|
||||||
if (cf.f == func)
|
if (cf.f == func)
|
||||||
lines.insert(-1, valueOf(cf.currentline()));
|
lines.insert(-1, valueOf(cf.currentline()));
|
||||||
@@ -239,7 +237,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;
|
||||||
int level = args.checkint(a++);
|
int level = args.checkint(a++);
|
||||||
int local = args.checkint(a++);
|
int local = args.checkint(a++);
|
||||||
return thread.callstack.getCallFrame(level).getLocal(local);
|
return callstack(thread).getCallFrame(level).getLocal(local);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,11 +295,11 @@ public class DebugLib extends OneArgFunction {
|
|||||||
case 'l': line=true; break;
|
case 'l': line=true; break;
|
||||||
case 'r': rtrn=true; break;
|
case 'r': rtrn=true; break;
|
||||||
}
|
}
|
||||||
thread.hookfunc = func;
|
hookfunc = func;
|
||||||
thread.hookcall = call;
|
hookcall = call;
|
||||||
thread.hookline = line;
|
hookline = line;
|
||||||
thread.hookcount = count;
|
hookcount = count;
|
||||||
thread.hookrtrn = rtrn;
|
hookrtrn = rtrn;
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +312,7 @@ public class DebugLib extends OneArgFunction {
|
|||||||
int level = args.checkint(a++);
|
int level = args.checkint(a++);
|
||||||
int local = args.checkint(a++);
|
int local = args.checkint(a++);
|
||||||
LuaValue value = args.arg(a++);
|
LuaValue value = args.arg(a++);
|
||||||
return thread.callstack.getCallFrame(level).setLocal(local, value);
|
return callstack(thread).getCallFrame(level).setLocal(local, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +370,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 = thread.callstack.traceback(level);
|
String tb = callstack(thread).traceback(level);
|
||||||
return valueOf(message!=null? message+"\n"+tb: tb);
|
return valueOf(message!=null? message+"\n"+tb: tb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,6 +401,223 @@ public class DebugLib extends OneArgFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onCall(LuaFunction f) {
|
||||||
|
if (inhook) return;
|
||||||
|
callstack().onCall(f);
|
||||||
|
if (hookcall && hookfunc != null)
|
||||||
|
callHook(CALL, NIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
|
||||||
|
if (inhook) return;
|
||||||
|
callstack().onCall(c, varargs, stack);
|
||||||
|
if (hookcall && hookfunc != null)
|
||||||
|
callHook(CALL, NIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInstruction(int pc, Varargs v, int top) {
|
||||||
|
if (inhook) return;
|
||||||
|
callstack().onInstruction(pc, v, top);
|
||||||
|
if (hookfunc == null) return;
|
||||||
|
if (hookcount > 0)
|
||||||
|
if (++bytecodes % hookcount == 0)
|
||||||
|
callHook(COUNT, NIL);
|
||||||
|
if (hookline) {
|
||||||
|
int newline = callstack().currentline();
|
||||||
|
if ( newline != lastline ) {
|
||||||
|
lastline = newline;
|
||||||
|
callHook(LINE, LuaValue.valueOf(newline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onReturn() {
|
||||||
|
if (inhook) return;
|
||||||
|
callstack().onReturn();
|
||||||
|
if (hookcall && hookfunc != null)
|
||||||
|
callHook(RETURN, NIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String traceback(int level) {
|
||||||
|
return callstack().traceback(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void callHook(LuaValue type, LuaValue arg) {
|
||||||
|
inhook = true;
|
||||||
|
try {
|
||||||
|
hookfunc.call(type, arg);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
inhook = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CallStack callstack() {
|
||||||
|
return callstack(globals.running_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
CallStack callstack(LuaThread t) {
|
||||||
|
if (t.callstack == null)
|
||||||
|
t.callstack = new CallStack();
|
||||||
|
return (CallStack) t.callstack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CallStack {
|
||||||
|
final static CallFrame[] EMPTY = {};
|
||||||
|
CallFrame[] frame = EMPTY;
|
||||||
|
int calls = 0;
|
||||||
|
|
||||||
|
CallStack() {}
|
||||||
|
|
||||||
|
int currentline() {
|
||||||
|
return calls > 0? frame[calls-1].currentline(): -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallFrame pushcall() {
|
||||||
|
if (calls >= frame.length) {
|
||||||
|
int n = Math.max(4, frame.length * 3 / 2);
|
||||||
|
CallFrame[] f = new CallFrame[n];
|
||||||
|
System.arraycopy(frame, 0, f, 0, frame.length);
|
||||||
|
for (int i = frame.length; i < n; ++i)
|
||||||
|
f[i] = new CallFrame();
|
||||||
|
frame = f;
|
||||||
|
}
|
||||||
|
return frame[calls++];
|
||||||
|
}
|
||||||
|
|
||||||
|
final void onCall(LuaFunction function) {
|
||||||
|
pushcall().set(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
final void onCall(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
||||||
|
pushcall().set(function, varargs, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
final void onReturn() {
|
||||||
|
if (calls > 0)
|
||||||
|
frame[--calls].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
final void onInstruction(int pc, Varargs v, int top) {
|
||||||
|
frame[calls-1].instr(pc, v, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the traceback starting at a specific level.
|
||||||
|
* @param level
|
||||||
|
* @return String containing the traceback.
|
||||||
|
*/
|
||||||
|
String traceback(int level) {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
sb.append( "stack traceback:" );
|
||||||
|
DebugLib.CallFrame c = getCallFrame(level);
|
||||||
|
if (c != null) {
|
||||||
|
sb.append("\n\t");
|
||||||
|
sb.append( c.sourceline() );
|
||||||
|
sb.append( " in " );
|
||||||
|
while ( (c = getCallFrame(++level)) != null ) {
|
||||||
|
sb.append( c.tracename() );
|
||||||
|
sb.append( "\n\t" );
|
||||||
|
sb.append( c.sourceline() );
|
||||||
|
sb.append( " in " );
|
||||||
|
}
|
||||||
|
sb.append( "main chunk" );
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugLib.CallFrame getCallFrame(int level) {
|
||||||
|
if (level < 1 || level >= calls)
|
||||||
|
return null;
|
||||||
|
return frame[calls-level];
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugLib.CallFrame findCallFrame(LuaValue func) {
|
||||||
|
for (int i = 1; i <= calls; ++i)
|
||||||
|
if (frame[calls-i].f == func)
|
||||||
|
return frame[i];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CallFrame {
|
||||||
|
LuaFunction f;
|
||||||
|
int pc;
|
||||||
|
int top;
|
||||||
|
Varargs v;
|
||||||
|
LuaValue[] stack;
|
||||||
|
boolean tail;
|
||||||
|
void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
|
||||||
|
this.f = function;
|
||||||
|
this.v = varargs;
|
||||||
|
this.stack = stack;
|
||||||
|
this.tail = false;
|
||||||
|
}
|
||||||
|
void set(LuaFunction function) {
|
||||||
|
this.f = function;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
this.f = null;
|
||||||
|
this.v = null;
|
||||||
|
this.stack = null;
|
||||||
|
}
|
||||||
|
void instr(int pc, Varargs v, int top) {
|
||||||
|
this.pc = pc;
|
||||||
|
this.v = v;
|
||||||
|
this.top = top;
|
||||||
|
if (f.checkclosure().p.code[pc] == Lua.OP_TAILCALL)
|
||||||
|
this.tail = true;
|
||||||
|
if (TRACE)
|
||||||
|
Print.printState(f.checkclosure(), pc, stack, top, v);
|
||||||
|
}
|
||||||
|
Varargs getLocal(int i) {
|
||||||
|
LuaString name = getlocalname(i);
|
||||||
|
if ( name != null )
|
||||||
|
return varargsOf( name, stack[i-1] );
|
||||||
|
else
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
Varargs setLocal(int i, LuaValue value) {
|
||||||
|
LuaString name = getlocalname(i);
|
||||||
|
if ( name != null ) {
|
||||||
|
stack[i-1] = value;
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int currentline() {
|
||||||
|
if ( !f.isclosure() ) return -1;
|
||||||
|
int[] li = f.checkclosure().p.lineinfo;
|
||||||
|
return li==null || pc<0 || pc>=li.length? -1: li[pc];
|
||||||
|
}
|
||||||
|
String sourceline() {
|
||||||
|
if ( !f.isclosure() ) return f.tojstring();
|
||||||
|
String s = f.checkclosure().p.source.tojstring();
|
||||||
|
int line = currentline();
|
||||||
|
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
|
||||||
|
}
|
||||||
|
String tracename() {
|
||||||
|
LuaString[] kind = getfuncname(this);
|
||||||
|
if ( kind == null )
|
||||||
|
return "function ?";
|
||||||
|
return "function "+kind[0].tojstring();
|
||||||
|
}
|
||||||
|
LuaString getlocalname(int index) {
|
||||||
|
if ( !f.isclosure() ) return null;
|
||||||
|
return f.checkclosure().p.getlocalname(index, pc);
|
||||||
|
}
|
||||||
|
String tojstring() {
|
||||||
|
return tracename()+" "+sourceline();
|
||||||
|
}
|
||||||
|
boolean istailcall() {
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static LuaString findupvalue(LuaClosure c, int up) {
|
static LuaString findupvalue(LuaClosure c, int up) {
|
||||||
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
|
||||||
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
|
||||||
@@ -426,7 +641,7 @@ public class DebugLib extends OneArgFunction {
|
|||||||
if (!x) throw new RuntimeException("lua_assert failed");
|
if (!x) throw new RuntimeException("lua_assert failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LuaString[] getfuncname(CallFrame frame) {
|
public static LuaString[] getfuncname(DebugLib.CallFrame frame) {
|
||||||
if (!frame.f.isclosure())
|
if (!frame.f.isclosure())
|
||||||
return new LuaString[] { frame.f.strvalue(), JAVA };
|
return new LuaString[] { frame.f.strvalue(), JAVA };
|
||||||
Prototype p = frame.f.checkclosure().p;
|
Prototype p = frame.f.checkclosure().p;
|
||||||
@@ -572,6 +787,4 @@ public class DebugLib extends OneArgFunction {
|
|||||||
}
|
}
|
||||||
return setreg;
|
return setreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,10 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
WeakReference luathr_ref;
|
WeakReference luathr_ref;
|
||||||
LuaValue function;
|
LuaValue function;
|
||||||
WeakReference func_ref;
|
WeakReference func_ref;
|
||||||
LuaValue env;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
LuaThread.thread_orphan_check_interval = 5;
|
LuaThread.thread_orphan_check_interval = 5;
|
||||||
env = JsePlatform.standardGlobals();
|
globals = JsePlatform.standardGlobals();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void tearDown() {
|
protected void tearDown() {
|
||||||
@@ -53,17 +52,17 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testCollectOrphanedNormalThread() throws Exception {
|
public void testCollectOrphanedNormalThread() throws Exception {
|
||||||
function = new NormalFunction();
|
function = new NormalFunction(globals);
|
||||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCollectOrphanedEarlyCompletionThread() throws Exception {
|
public void testCollectOrphanedEarlyCompletionThread() throws Exception {
|
||||||
function = new EarlyCompletionFunction();
|
function = new EarlyCompletionFunction(globals);
|
||||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCollectOrphanedAbnormalThread() throws Exception {
|
public void testCollectOrphanedAbnormalThread() throws Exception {
|
||||||
function = new AbnormalFunction();
|
function = new AbnormalFunction(globals);
|
||||||
doTest(LuaValue.FALSE, LuaValue.valueOf("abnormal condition"));
|
doTest(LuaValue.FALSE, LuaValue.valueOf("abnormal condition"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +75,7 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
"print('leakage in closure.3, arg is '..arg)\n" +
|
"print('leakage in closure.3, arg is '..arg)\n" +
|
||||||
"return 'done'\n";
|
"return 'done'\n";
|
||||||
LuaC.install();
|
LuaC.install();
|
||||||
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env);
|
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", globals);
|
||||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +91,7 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
"end\n" +
|
"end\n" +
|
||||||
"print( 'pcall-closre.result:', pcall( f, ... ) )\n";
|
"print( 'pcall-closre.result:', pcall( f, ... ) )\n";
|
||||||
LuaC.install();
|
LuaC.install();
|
||||||
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env);
|
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", globals);
|
||||||
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
doTest(LuaValue.TRUE, LuaValue.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,12 +108,11 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
"end\n" +
|
"end\n" +
|
||||||
"load(f)()\n";
|
"load(f)()\n";
|
||||||
LuaC.install();
|
LuaC.install();
|
||||||
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", env);
|
function = LoadState.load(new ByteArrayInputStream(script.getBytes()), "script", "bt", globals);
|
||||||
doTest(LuaValue.TRUE, LuaValue.ONE);
|
doTest(LuaValue.TRUE, LuaValue.ONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTest(LuaValue status2, LuaValue value2) throws Exception {
|
private void doTest(LuaValue status2, LuaValue value2) throws Exception {
|
||||||
globals = JsePlatform.standardGlobals();
|
|
||||||
luathread = new LuaThread(globals, function);
|
luathread = new LuaThread(globals, function);
|
||||||
luathr_ref = new WeakReference(luathread);
|
luathr_ref = new WeakReference(luathread);
|
||||||
func_ref = new WeakReference(function);
|
func_ref = new WeakReference(function);
|
||||||
@@ -144,7 +142,11 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class NormalFunction extends OneArgFunction {
|
static class NormalFunction extends OneArgFunction {
|
||||||
|
final Globals globals;
|
||||||
|
public NormalFunction(Globals globals) {
|
||||||
|
this.globals = globals;
|
||||||
|
}
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
System.out.println("in normal.1, arg is "+arg);
|
System.out.println("in normal.1, arg is "+arg);
|
||||||
arg = globals.yield(ONE).arg1();
|
arg = globals.yield(ONE).arg1();
|
||||||
@@ -155,7 +157,11 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EarlyCompletionFunction extends OneArgFunction {
|
static class EarlyCompletionFunction extends OneArgFunction {
|
||||||
|
final Globals globals;
|
||||||
|
public EarlyCompletionFunction(Globals globals) {
|
||||||
|
this.globals = globals;
|
||||||
|
}
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
System.out.println("in early.1, arg is "+arg);
|
System.out.println("in early.1, arg is "+arg);
|
||||||
arg = globals.yield(ONE).arg1();
|
arg = globals.yield(ONE).arg1();
|
||||||
@@ -164,17 +170,11 @@ public class OrphanedThreadTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AbnormalFunction extends OneArgFunction {
|
static class AbnormalFunction extends OneArgFunction {
|
||||||
public LuaValue call(LuaValue arg) {
|
final Globals globals;
|
||||||
System.out.println("in abnormal.1, arg is "+arg);
|
public AbnormalFunction(Globals globals) {
|
||||||
arg = globals.yield(ONE).arg1();
|
this.globals = globals;
|
||||||
System.out.println("in abnormal.2, arg is "+arg);
|
}
|
||||||
error("abnormal condition");
|
|
||||||
return ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClosureFunction extends OneArgFunction {
|
|
||||||
public LuaValue call(LuaValue arg) {
|
public LuaValue call(LuaValue arg) {
|
||||||
System.out.println("in abnormal.1, arg is "+arg);
|
System.out.println("in abnormal.1, arg is "+arg);
|
||||||
arg = globals.yield(ONE).arg1();
|
arg = globals.yield(ONE).arg1();
|
||||||
|
|||||||
Reference in New Issue
Block a user