diff --git a/src/core/org/luaj/lib/DebugLib.java b/src/core/org/luaj/lib/DebugLib.java index ebf1404f..606ec0f2 100644 --- a/src/core/org/luaj/lib/DebugLib.java +++ b/src/core/org/luaj/lib/DebugLib.java @@ -168,12 +168,12 @@ public class DebugLib extends LFunction { threadVm = vm.checkthread(2).vm; vm.remove(2); } - LFunction func = vm.checkfunction(2); - LString str = vm.checklstring(3); + LFunction func = vm.isnoneornil(2)? null: vm.checkfunction(2); + String str = vm.optstring(3,""); int count = vm.optint(4,0); int mask = 0; - for ( int i=0; i= 4 ) { threadVm = vm.checkthread(2).vm; vm.remove(2); } - if ( vm.gettop() >= 3 ) { - what = vm.tostring(3); - } + String what = vm.optstring(3, "nSluf"); if ( vm.isnumber(2) ) { ci = this.getcallinfo(vm, threadVm, vm.tointeger(2)); closure = ci.closure; @@ -223,20 +220,20 @@ public class DebugLib extends LFunction { for (int i = 0, n = what.length(); i < n; i++) { switch (what.charAt(i)) { case 'S': { - info.put("source", (closure!=null? closure.p.source: new LString("@?"))); - info.put("short_src", (closure!=null? closure.p.source.substring(1, closure.p.source.m_length-1): new LString("?"))); + String s = (closure!=null? closure.p.source.toJavaString(): "=?"); + info.put("source", new LString(s.replace('@','='))); + info.put("short_src", new LString(s.substring(1))); info.put("linedefined", (closure!=null? closure.p.linedefined: 0)); info.put("lastlinedefined", (closure!=null? closure.p.lastlinedefined: 0)); - info.put("what", new LString(what)); + info.put("what", new LString("Lua")); break; } case 'l': { - info.put( "currentline", (ci!=null? ci.pc: 0) ); + info.put( "currentline", currentline(threadVm, ci, func) ); break; } case 'u': { info.put("nups", (closure!=null? closure.p.nups: 0)); - info.put("what", new LString(what)); break; } case 'n': { @@ -246,22 +243,40 @@ public class DebugLib extends LFunction { break; } case 'f': { - if ( func != null ) - info.put( "func", func ); + info.put( "func", closure ); break; } case 'L': { LTable lines = new LTable(); info.put("activelines", lines); - if ( closure != null ) - for ( int j=0, k=1; j=0; --j ) + if ( threadVm.calls[j].closure == func ) { + int line = threadVm.debugGetLineNumber(ci); + if ( line >= 0 ) + lines.put(k++, LInteger.valueOf(line)); + } break; } } } } + private int currentline(LuaState vm, CallInfo ci, LFunction func) { + if ( ci == null ) { + ci = findcallinfo(vm, func); + if ( ci == null ) + return -1; + } + return vm.debugGetLineNumber(ci); + } + + private CallInfo findcallinfo(LuaState vm, LFunction func) { + for ( int i=vm.cc; i>=0; --i ) + if ( vm.calls[i].closure == func ) + return vm.calls[i]; + return null; + } + private LString getlocalname (LPrototype f, int local_number, int pc) { int i; for (i = 0; i= 4 ) { threadVm = vm.checkthread(2).vm; vm.remove(2); @@ -432,8 +446,10 @@ public class DebugLib extends LFunction { level = vm.optint(3,1); if ( vm.gettop() >= 2 ) message = vm.tostring(2)+"\n"; - message += threadVm.getStackTrace(level); + String trace = threadVm.getStackTrace(level-1); + if ( trace.endsWith("\n") ) + trace = trace.substring(0,trace.length()-1); vm.resettop(); - vm.pushstring(sb.toString()); + vm.pushstring(message+trace); } } diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index 5c2bd86b..d2c40685 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -110,7 +110,7 @@ public class LuaState extends Lua { private int hookcount; private LFunction hookfunc; private int hookincr; - private int hookline; + private int hookline,hookcc; protected void debugAssert(boolean b) {} @@ -714,7 +714,7 @@ public class LuaState extends Lua { // call hook if ( hooksenabled ) { - debugCallHooks( ci.pc-1 ); + debugCallHooks( ); } // make or set up the call @@ -737,7 +737,7 @@ public class LuaState extends Lua { case LuaState.OP_TAILCALL: { // return hook if ( hooksenabled ) { - debugTailReturnHooks( ci.pc-1 ); + debugTailReturnHooks( ); } // close up values @@ -785,7 +785,7 @@ public class LuaState extends Lua { case LuaState.OP_RETURN: { // return hook if ( hooksenabled ) { - debugReturnHooks( ci.pc-1 ); + debugReturnHooks( ); } // close up values @@ -2414,8 +2414,9 @@ public class LuaState extends Lua { private void debugBytecodeHooks(int pc) { if ( hookfunc != null && (hookmask & LUA_MASKLINE) != 0 ) { int line = debugGetLineNumber(calls[cc]); - if ( line != hookline ) { + if ( (line != hookline || cc != hookcc) && line >= 0 ) { hookline = line; + hookcc = cc; debugCallHook(LUA_HOOKLINE, line); } if (hookcount != 0) { @@ -2427,52 +2428,56 @@ public class LuaState extends Lua { } } - private void debugCallHooks(int pc) { + private void debugCallHooks() { if ( hookfunc != null && ((hookmask & LUA_MASKCALL) != 0) ) { debugCallHook(LUA_HOOKCALL, debugGetLineNumber(calls[cc])); - hookline = -1; } } - private void debugReturnHooks(int pc) { + private void debugReturnHooks() { if ( hookfunc != null && ((hookmask & LUA_MASKRET) != 0) ) { debugCallHook(LUA_HOOKRET, debugGetLineNumber(calls[cc])); - hookline = -1; } } - private void debugTailReturnHooks(int pc) { + private void debugTailReturnHooks() { if ( hookfunc != null && ((hookmask & LUA_MASKRET) != 0) ) { debugCallHook(LUA_HOOKTAILRET, debugGetLineNumber(calls[cc])); - hookline = -1; } } - private int debugGetLineNumber(CallInfo ci) { - int[] lineNumbers = ci.closure.p.lineinfo; - int pc = getCurrentPc(ci); - int line = (lineNumbers != null && lineNumbers.length > pc ? - lineNumbers[pc] : - -1); - return line; + public int debugGetLineNumber(CallInfo ci) { + int[] li = ci.closure.p.lineinfo; + int pc = ci.pc - 1; + if ( li != null && pc >= 0 && pc < li.length ) + return li[pc]; + return -1; } - private void debugCallHook(int mask, int newline) { + private void debugCallHook(int mask, int line) { int prevmask = hookmask; + int oldtop = top; + LValue lineval = LNil.NIL; try { + if ( cc >= 0 ) + top = base + this.calls[cc].closure.p.maxstacksize; hookmask = 0; this.pushfunction(hookfunc); switch ( mask ) { - default: this.pushstring("line"); break; case LUA_HOOKCOUNT: this.pushstring("count"); break; case LUA_HOOKCALL: this.pushstring("call"); break; case LUA_HOOKRET: this.pushstring("return"); break; - case LUA_HOOKTAILRET: this.pushstring("tail return"); break; + case LUA_HOOKTAILRET: this.pushstring("return"); break; + default: + lineval = LInteger.valueOf(line); + this.pushstring("line"); + break; } - this.pushinteger(newline); + this.pushlvalue(lineval); this.pcall(2, 0, 0); } finally { hookmask = prevmask; + top = oldtop; } } } diff --git a/src/test/res/debuglib.lua b/src/test/res/debuglib.lua index 676bd2ac..7626d409 100644 --- a/src/test/res/debuglib.lua +++ b/src/test/res/debuglib.lua @@ -117,29 +117,32 @@ print( pcall( debug.getmetatable, 1 ) ) -- print( pcall( debug.setmetatable, 1, {} ) ) -- print( pcall( debug.setmetatable, 1, nil ) ) - ---[[ -local f = function(a) - return 'f:'..tostring(a)..'|'..tostring(b) +print( '----- debug.getinfo' ) +local printfield = function(tbl, field) + local x = tbl[field] + if x == nil then return end + local typ = type(x) + if typ=='table' then + x = '{'..table.concat(x,',')..'}' + elseif typ=='function' then + x = typ + end + print( ' '..field..': '..tostring(x) ) end -local s,e - - +local fields = { 'source', 'short_src', 'what', + 'currentline', 'linedefined', 'lastlinedefined', + 'nups', 'func', 'activelines' } local printinfo = function(...) for i,a in ipairs(arg) do if type(a) == 'table' then - print( ' source: '..tostring(a.source) ) - print( ' short_src: '..tostring(a.short_src) ) - print( ' what: '..tostring(a.what) ) - print( ' currentline: '..tostring(a.currentline) ) - print( ' linedefined: '..tostring(a.linedefined) ) - print( ' lastlinedefined: '..tostring(a.lastlinedefined) ) + for j,field in ipairs(fields) do + printfield( a, field) + end else print( tostring(a) ) end end end - function test() local x = 5 function f() @@ -148,6 +151,20 @@ function test() end function g() x = x - 1 + print( '---' ) + printinfo( 'debug.getinfo(1)', debug.getinfo(1) ) + printinfo( 'debug.getinfo(1,"l")', debug.getinfo(1, "l") ) + printinfo( 'debug.getinfo(1,"fL")', debug.getinfo(1, "fL") ) + printinfo( 'debug.getinfo(2)', debug.getinfo(2) ) + printinfo( 'debug.getinfo(2,"l")', debug.getinfo(2, "l") ) + printinfo( 'debug.getinfo(2,"fL")', debug.getinfo(2, "fL") ) + --[[ + for i=1,3 do + printinfo( 'debug.traceback("msg")', debug.traceback('msg') ) + printinfo( 'debug.traceback("another",'..i..')', debug.traceback('another',i) ) + end + --]] + print( '---' ) return x end print(f()) @@ -155,10 +172,53 @@ function test() return f, g end +local options = "nSlufL" local e,f,g = pcall( test ) print( 'e,f,g', e, type(f), type(g) ) +printinfo( 'debug.getinfo(f)', pcall(debug.getinfo, f) ) +printinfo( 'debug.getinfo(f,"'..options..'")', pcall(debug.getinfo, f, options) ) +for j=1,6 do + local opts = options:sub(j,j) + printinfo( 'debug.getinfo(f,"'..opts..'")', pcall(debug.getinfo, f, opts) ) +end +printinfo( 'debug.getinfo(g)', pcall(debug.getinfo, g) ) +printinfo( 'debug.getinfo(test)', pcall(debug.getinfo, test) ) -printinfo( 'debug.getinfo(f,"Sl")', pcall(debug.getinfo, f, "Sl") ) -printinfo( 'debug.getinfo(g,"Sl")', pcall(debug.getinfo, g, "Sl") ) -printinfo( 'debug.getinfo(test,"Sl")', pcall(debug.getinfo, test, "Sl") ) ---]] \ No newline at end of file +print( '----- debug.sethook, debug.gethook' ) +f = function(x) + g = function(y) + return math.min(x,h) + end + local a = g(x) + return a + a +end +local hook = function(...) + print( ' ... in hook', ... ) +end +local tryfunc = function(hook,mask,func,arg) + local x,f,h,m + pcall( function() + debug.sethook(hook,mask) + x = func(arg) + f,h,m = debug.gethook() + end ) + debug.sethook() + return x,f,h,m +end + +local tryhooks = function(mask) + local s1,a1,b1,c1,d1 = pcall( tryfunc, hook, mask, f, 333 ) + print( 'hook = '..mask..' -> '.. + 'result='..tostring(s1)..','..tostring(a1)..','.. + type(b1)..','..type(c1)..','.. + tostring(b1==f)..','..tostring(c1==hook)..','.. + tostring(d1)..' ' ) +end +--[[ +tryhooks("c") +tryhooks("r") +tryhooks("l") +tryhooks("crl") +--]] + + \ No newline at end of file