summaryrefslogtreecommitdiff
path: root/libs/liblua/src/ldebug.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/liblua/src/ldebug.c')
-rw-r--r--libs/liblua/src/ldebug.c131
1 files changed, 78 insertions, 53 deletions
diff --git a/libs/liblua/src/ldebug.c b/libs/liblua/src/ldebug.c
index 8cb00e51a1..1feaab229f 100644
--- a/libs/liblua/src/ldebug.c
+++ b/libs/liblua/src/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);
@@ -48,10 +46,16 @@ static int currentpc (CallInfo *ci) {
/*
** Get a "base line" to find the line corresponding to an instruction.
-** For that, search the array of absolute line info for the largest saved
-** instruction smaller or equal to the wanted instruction. A special
-** case is when there is no absolute info or the instruction is before
-** the first absolute one.
+** Base lines are regularly placed at MAXIWTHABS intervals, so usually
+** an integer division gets the right place. When the source file has
+** large sequences of empty/comment lines, it may need extra entries,
+** so the original estimate needs a correction.
+** If the original estimate is -1, the initial 'if' ensures that the
+** 'while' will run at least once.
+** The assertion that the estimate is a lower bound for the correct base
+** is valid as long as the debug info has been generated with the same
+** value for MAXIWTHABS or smaller. (Previous releases use a little
+** smaller value.)
*/
static int getbaseline (const Proto *f, int pc, int *basepc) {
if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
@@ -59,20 +63,12 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
return f->linedefined;
}
else {
- unsigned int i;
- if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc)
- i = f->sizeabslineinfo - 1; /* instruction is after last saved one */
- else { /* binary search */
- unsigned int j = f->sizeabslineinfo - 1; /* pc < anchorlines[j] */
- i = 0; /* abslineinfo[i] <= pc */
- while (i < j - 1) {
- unsigned int m = (j + i) / 2;
- if (pc >= f->abslineinfo[m].pc)
- i = m;
- else
- j = m;
- }
- }
+ int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
+ /* estimate must be a lower bond of the correct base */
+ lua_assert(i < 0 ||
+ (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
+ while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
+ i++; /* low estimate; adjust it */
*basepc = f->abslineinfo[i].pc;
return f->abslineinfo[i].line;
}
@@ -305,8 +301,8 @@ static void collectvalidlines (lua_State *L, Closure *f) {
sethvalue2s(L, L->top, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
- for (i = 0; i < p->sizelineinfo; i++) { /* for all lines with code */
- currentline = nextline(p, currentline, i);
+ for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
+ currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
}
@@ -629,12 +625,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
case OP_LEN: tm = TM_LEN; break;
case OP_CONCAT: tm = TM_CONCAT; break;
case OP_EQ: tm = TM_EQ; break;
- case OP_LT: case OP_LE: case OP_LTI: case OP_LEI:
- *name = "order"; /* '<=' can call '__lt', etc. */
- return "metamethod";
- case OP_CLOSE: case OP_RETURN:
- *name = "close";
- return "metamethod";
+ /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
+ case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
+ case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
+ case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
default:
return NULL; /* cannot find a reasonable name */
}
@@ -647,14 +641,18 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
/*
-** The subtraction of two potentially unrelated pointers is
-** not ISO C, but it should not crash a program; the subsequent
-** checks are ISO C and ensure a correct result.
+** Check whether pointer 'o' points to some value in the stack
+** frame of the current function. Because 'o' may not point to a
+** value in this stack, we cannot compare it with the region
+** boundaries (undefined behaviour in ISO C).
*/
static int isinstack (CallInfo *ci, const TValue *o) {
- StkId base = ci->func + 1;
- ptrdiff_t i = cast(StkId, o) - base;
- return (0 <= i && i < (ci->top - base) && s2v(base + i) == o);
+ StkId pos;
+ for (pos = ci->func + 1; pos < ci->top; pos++) {
+ if (o == s2v(pos))
+ return 1;
+ }
+ return 0; /* not found */
}
@@ -697,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
}
+l_noret luaG_callerror (lua_State *L, const TValue *o) {
+ CallInfo *ci = L->ci;
+ const char *name = NULL; /* to avoid warnings */
+ const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
+ if (what != NULL) {
+ const char *t = luaT_objtypename(L, o);
+ luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
+ }
+ else
+ luaG_typeerror(L, o, "call");
+}
+
+
l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
what, luaT_objtypename(L, o));
@@ -722,7 +733,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1,
*/
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
lua_Integer temp;
- if (!tointegerns(p1, &temp))
+ if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
p2 = p1;
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
}
@@ -780,16 +791,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));
}
@@ -797,20 +822,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' */
@@ -826,15 +850,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 */
}