summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-01-28 14:40:29 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-01-28 14:40:29 -0300
commit949187b049ce329c93d6639b91e244f2b208c807 (patch)
treee758128392692fe349087e457fc743ea4f56e4bb
parent58aa09a0b91cf81779d6710d7f9d855bb9d3712f (diff)
downloadlua-github-949187b049ce329c93d6639b91e244f2b208c807.tar.gz
Optimizations for line hook
The function 'changedline' tries harder to avoid calling 'luaG_getfuncline' plus small changes in the use of 'L->oldpc'.
-rw-r--r--lcode.c9
-rw-r--r--ldebug.c52
-rw-r--r--ldebug.h10
-rw-r--r--ldo.c9
4 files changed, 47 insertions, 33 deletions
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' */
}