diff --git a/lcode.c b/lcode.c index d8d353fe..9741d7cd 100644 --- a/lcode.c +++ b/lcode.c @@ -314,15 +314,6 @@ void luaK_patchtohere (FuncState *fs, int list) { } -/* -** MAXimum number of successive Instructions WiTHout ABSolute line -** information. -*/ -#if !defined(MAXIWTHABS) -#define MAXIWTHABS 120 -#endif - - /* limit for difference between lines in relative line info. */ #define LIMLINEDIFF 0x80 diff --git a/ldebug.c b/ldebug.c index 819550d7..8dfa18cf 100644 --- a/ldebug.c +++ b/ldebug.c @@ -33,8 +33,6 @@ #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) -/* inverse of 'pcRel' */ -#define invpcRel(pc, p) ((p)->code + (pc) + 1) static const char *funcnamefromcode (lua_State *L, CallInfo *ci, const char **name); @@ -791,16 +789,30 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { /* ** Check whether new instruction 'newpc' is in a different line from -** previous instruction 'oldpc'. +** previous instruction 'oldpc'. More often than not, 'newpc' is only +** one or a few instructions after 'oldpc' (it must be after, see +** caller), so try to avoid calling 'luaG_getfuncline'. If they are +** too far apart, there is a good chance of a ABSLINEINFO in the way, +** so it goes directly to 'luaG_getfuncline'. */ static int changedline (const Proto *p, int oldpc, int newpc) { if (p->lineinfo == NULL) /* no debug information? */ return 0; - while (oldpc++ < newpc) { - if (p->lineinfo[oldpc] != 0) - return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc)); + if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ + int delta = 0; /* line diference */ + int pc = oldpc; + for (;;) { + int lineinfo = p->lineinfo[++pc]; + if (lineinfo == ABSLINEINFO) + break; /* cannot compute delta; fall through */ + delta += lineinfo; + if (pc == newpc) + return (delta != 0); /* delta computed successfully */ + } } - return 0; /* no line changes between positions */ + /* either instructions are too far apart or there is an absolute line + info in the way; compute line difference explicitly */ + return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); } @@ -808,20 +820,19 @@ static int changedline (const Proto *p, int oldpc, int newpc) { ** Traces the execution of a Lua function. Called before the execution ** of each opcode, when debug is on. 'L->oldpc' stores the last ** instruction traced, to detect line changes. When entering a new -** function, 'npci' will be zero and will test as a new line without -** the need for 'oldpc'; so, 'oldpc' does not need to be initialized -** before. Some exceptional conditions may return to a function without -** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is -** reset to zero. (A wrong but valid 'oldpc' at most causes an extra -** call to a line hook.) +** function, 'npci' will be zero and will test as a new line whatever +** the value of 'oldpc'. Some exceptional conditions may return to +** a function without setting 'oldpc'. In that case, 'oldpc' may be +** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' +** at most causes an extra call to a line hook.) +** This function is not "Protected" when called, so it should correct +** 'L->top' before calling anything that can run the GC. */ int luaG_traceexec (lua_State *L, const Instruction *pc) { CallInfo *ci = L->ci; lu_byte mask = L->hookmask; const Proto *p = ci_func(ci)->p; int counthook; - /* 'L->oldpc' may be invalid; reset it in this case */ - int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ ci->u.l.trap = 0; /* don't need to stop again */ return 0; /* turn off 'trap' */ @@ -837,15 +848,16 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return 1; /* do not call hook again (VM yielded, so it did not move) */ } - if (!isIT(*(ci->u.l.savedpc - 1))) - L->top = ci->top; /* prepare top */ + if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ + L->top = ci->top; /* correct top */ if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ if (mask & LUA_MASKLINE) { + /* 'L->oldpc' may be invalid; use zero in this case */ + int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; int npci = pcRel(pc, p); - if (npci == 0 || /* call linehook when enter a new function, */ - pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ - changedline(p, oldpc, npci)) { /* enter new line */ + if (npci <= oldpc || /* call hook when jump back (loop), */ + changedline(p, oldpc, npci)) { /* or when enter new line */ int newline = luaG_getfuncline(p, npci); luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ } diff --git a/ldebug.h b/ldebug.h index 55b3ae09..8e912a8e 100644 --- a/ldebug.h +++ b/ldebug.h @@ -26,6 +26,16 @@ */ #define ABSLINEINFO (-0x80) + +/* +** MAXimum number of successive Instructions WiTHout ABSolute line +** information. +*/ +#if !defined(MAXIWTHABS) +#define MAXIWTHABS 120 +#endif + + LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos); diff --git a/ldo.c b/ldo.c index 80c79803..e8cccccb 100644 --- a/ldo.c +++ b/ldo.c @@ -331,6 +331,7 @@ void luaD_hook (lua_State *L, int event, int line, ** active. */ void luaD_hookcall (lua_State *L, CallInfo *ci) { + L->oldpc = 0; /* set 'oldpc' for new function */ if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */ int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL; @@ -343,9 +344,9 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) { /* -** Executes a call hook for Lua and C functions. This function is called -** whenever 'hookmask' is not zero, so it checks whether return hooks are -** active. +** Executes a return hook for Lua and C functions and sets/corrects +** 'oldpc'. (Note that this correction is needed by the line hook, so it +** is done even when return hooks are off.) */ static void rethook (lua_State *L, CallInfo *ci, int nres) { if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ @@ -363,7 +364,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { ci->func -= delta; } if (isLua(ci = ci->previous)) - L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */ + L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ }