mirror of
https://github.com/lua/lua
synced 2025-01-01 15:14:35 +03:00
Fixed bug in line info. when using 'not' operator
When creating code for a jump on a 'not' condition, the code generator was removing an instruction (the OP_NOT) without adjusting its corresponding line information. This fix also added tests for this case and extra functionality in the test library to debug line info. structures.
This commit is contained in:
parent
9a825f6bb9
commit
4d5de1c1fb
76
lcode.c
76
lcode.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lcode.c,v 2.160 2018/03/16 14:22:09 roberto Exp roberto $
|
** $Id: lcode.c $
|
||||||
** Code generator for Lua
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -309,10 +309,19 @@ void luaK_patchclose (FuncState *fs, int list) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MAXimum number of successive Instructions WiTHout ABSolute line
|
||||||
|
** information.
|
||||||
|
*/
|
||||||
#if !defined(MAXIWTHABS)
|
#if !defined(MAXIWTHABS)
|
||||||
#define MAXIWTHABS 120
|
#define MAXIWTHABS 120
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* limit for difference between lines in relative line info. */
|
||||||
|
#define LIMLINEDIFF 0x80
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Save line info for a new instruction. If difference from last line
|
** Save line info for a new instruction. If difference from last line
|
||||||
** does not fit in a byte, of after that many instructions, save a new
|
** does not fit in a byte, of after that many instructions, save a new
|
||||||
@ -320,14 +329,15 @@ void luaK_patchclose (FuncState *fs, int list) {
|
|||||||
** in 'lineinfo' signals the existence of this absolute information.)
|
** in 'lineinfo' signals the existence of this absolute information.)
|
||||||
** Otherwise, store the difference from last line in 'lineinfo'.
|
** Otherwise, store the difference from last line in 'lineinfo'.
|
||||||
*/
|
*/
|
||||||
static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) {
|
static void savelineinfo (FuncState *fs, Proto *f, int line) {
|
||||||
int linedif = line - fs->previousline;
|
int linedif = line - fs->previousline;
|
||||||
if (abs(linedif) >= 0x80 || fs->iwthabs++ > MAXIWTHABS) {
|
int pc = fs->pc - 1; /* last instruction coded */
|
||||||
|
if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) {
|
||||||
luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
|
luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
|
||||||
f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
|
f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
|
||||||
f->abslineinfo[fs->nabslineinfo].pc = pc;
|
f->abslineinfo[fs->nabslineinfo].pc = pc;
|
||||||
f->abslineinfo[fs->nabslineinfo++].line = line;
|
f->abslineinfo[fs->nabslineinfo++].line = line;
|
||||||
linedif = ABSLINEINFO; /* signal there is absolute information */
|
linedif = ABSLINEINFO; /* signal that there is absolute information */
|
||||||
fs->iwthabs = 0; /* restart counter */
|
fs->iwthabs = 0; /* restart counter */
|
||||||
}
|
}
|
||||||
luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
|
luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
|
||||||
@ -337,6 +347,37 @@ static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove line information from the last instruction.
|
||||||
|
** If line information for that instruction is absolute, set 'iwthabs'
|
||||||
|
** above its max to force the new (replacing) instruction to have
|
||||||
|
** absolute line info, too.
|
||||||
|
*/
|
||||||
|
static void removelastlineinfo (FuncState *fs) {
|
||||||
|
Proto *f = fs->f;
|
||||||
|
int pc = fs->pc - 1; /* last instruction coded */
|
||||||
|
if (f->lineinfo[pc] != ABSLINEINFO) { /* relative line info? */
|
||||||
|
fs->previousline -= f->lineinfo[pc]; /* last line saved */
|
||||||
|
fs->iwthabs--;
|
||||||
|
}
|
||||||
|
else { /* absolute line information */
|
||||||
|
fs->nabslineinfo--; /* remove it */
|
||||||
|
lua_assert(f->abslineinfo[fs->nabslineinfo].pc = pc);
|
||||||
|
fs->iwthabs = MAXIWTHABS + 1; /* force next line info to be absolute */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove the last instruction created, correcting line information
|
||||||
|
** accordingly.
|
||||||
|
*/
|
||||||
|
static void removelastinstruction (FuncState *fs) {
|
||||||
|
removelastlineinfo(fs);
|
||||||
|
fs->pc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Emit instruction 'i', checking for array sizes and saving also its
|
** Emit instruction 'i', checking for array sizes and saving also its
|
||||||
** line information. Return 'i' position.
|
** line information. Return 'i' position.
|
||||||
@ -346,9 +387,9 @@ static int luaK_code (FuncState *fs, Instruction i) {
|
|||||||
/* put new instruction in code array */
|
/* put new instruction in code array */
|
||||||
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
|
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||||
MAX_INT, "opcodes");
|
MAX_INT, "opcodes");
|
||||||
f->code[fs->pc] = i;
|
f->code[fs->pc++] = i;
|
||||||
savelineinfo(fs, f, fs->pc, fs->ls->lastline);
|
savelineinfo(fs, f, fs->ls->lastline);
|
||||||
return fs->pc++;
|
return fs->pc - 1; /* index of new instruction */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -986,7 +1027,7 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
|
|||||||
if (e->k == VRELOC) {
|
if (e->k == VRELOC) {
|
||||||
Instruction ie = getinstruction(fs, e);
|
Instruction ie = getinstruction(fs, e);
|
||||||
if (GET_OPCODE(ie) == OP_NOT) {
|
if (GET_OPCODE(ie) == OP_NOT) {
|
||||||
fs->pc--; /* remove previous OP_NOT */
|
removelastinstruction(fs); /* remove previous OP_NOT */
|
||||||
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
|
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
|
||||||
}
|
}
|
||||||
/* else go through */
|
/* else go through */
|
||||||
@ -1572,23 +1613,12 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Change line information associated with current position. If that
|
** Change line information associated with current position, by removing
|
||||||
** information is absolute, just change it and correct 'previousline'.
|
** previous info and adding it again with new line.
|
||||||
** Otherwise, restore 'previousline' to its value before saving the
|
|
||||||
** current position and than saves the line information again, with the
|
|
||||||
** new line.
|
|
||||||
*/
|
*/
|
||||||
void luaK_fixline (FuncState *fs, int line) {
|
void luaK_fixline (FuncState *fs, int line) {
|
||||||
Proto *f = fs->f;
|
removelastlineinfo(fs);
|
||||||
if (f->lineinfo[fs->pc - 1] == ABSLINEINFO) {
|
savelineinfo(fs, fs->f, line);
|
||||||
lua_assert(f->abslineinfo[fs->nabslineinfo - 1].pc == fs->pc - 1);
|
|
||||||
f->abslineinfo[fs->nabslineinfo - 1].line = line;
|
|
||||||
fs->previousline = line;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fs->previousline -= f->lineinfo[fs->pc - 1]; /* undo previous info. */
|
|
||||||
savelineinfo(fs, f, fs->pc - 1, line); /* redo it */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
22
ltests.c
22
ltests.c
@ -526,7 +526,8 @@ static char *buildop (Proto *p, int pc, char *buff) {
|
|||||||
OpCode o = GET_OPCODE(i);
|
OpCode o = GET_OPCODE(i);
|
||||||
const char *name = opnames[o];
|
const char *name = opnames[o];
|
||||||
int line = luaG_getfuncline(p, pc);
|
int line = luaG_getfuncline(p, pc);
|
||||||
sprintf(buff, "(%4d) %4d - ", line, pc);
|
int lineinfo = (p->lineinfo != NULL) ? p->lineinfo[pc] : 0;
|
||||||
|
sprintf(buff, "(%2d - %4d) %4d - ", lineinfo, line, pc);
|
||||||
switch (getOpMode(o)) {
|
switch (getOpMode(o)) {
|
||||||
case iABC:
|
case iABC:
|
||||||
sprintf(buff+strlen(buff), "%-12s%4d %4d %4d%s", name,
|
sprintf(buff+strlen(buff), "%-12s%4d %4d %4d%s", name,
|
||||||
@ -621,6 +622,24 @@ static int listk (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int listabslineinfo (lua_State *L) {
|
||||||
|
Proto *p;
|
||||||
|
int i;
|
||||||
|
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
|
||||||
|
1, "Lua function expected");
|
||||||
|
p = getproto(obj_at(L, 1));
|
||||||
|
luaL_argcheck(L, p->abslineinfo != NULL, 1, "function has no debug info");
|
||||||
|
lua_createtable(L, 2 * p->sizeabslineinfo, 0);
|
||||||
|
for (i=0; i < p->sizeabslineinfo; i++) {
|
||||||
|
lua_pushinteger(L, p->abslineinfo[i].pc);
|
||||||
|
lua_rawseti(L, -2, 2 * i + 1);
|
||||||
|
lua_pushinteger(L, p->abslineinfo[i].line);
|
||||||
|
lua_rawseti(L, -2, 2 * i + 2);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int listlocals (lua_State *L) {
|
static int listlocals (lua_State *L) {
|
||||||
Proto *p;
|
Proto *p;
|
||||||
int pc = cast_int(luaL_checkinteger(L, 2)) - 1;
|
int pc = cast_int(luaL_checkinteger(L, 2)) - 1;
|
||||||
@ -1682,6 +1701,7 @@ static const struct luaL_Reg tests_funcs[] = {
|
|||||||
{"listcode", listcode},
|
{"listcode", listcode},
|
||||||
{"printcode", printcode},
|
{"printcode", printcode},
|
||||||
{"listk", listk},
|
{"listk", listk},
|
||||||
|
{"listabslineinfo", listabslineinfo},
|
||||||
{"listlocals", listlocals},
|
{"listlocals", listlocals},
|
||||||
{"loadlib", loadlib},
|
{"loadlib", loadlib},
|
||||||
{"checkpanic", checkpanic},
|
{"checkpanic", checkpanic},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
-- $Id: errors.lua,v 1.97 2017/11/28 15:31:56 roberto Exp $
|
-- $Id: errors.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file all.lua
|
||||||
|
|
||||||
print("testing errors")
|
print("testing errors")
|
||||||
@ -299,7 +299,7 @@ end
|
|||||||
local function lineerror (s, l)
|
local function lineerror (s, l)
|
||||||
local err,msg = pcall(load(s))
|
local err,msg = pcall(load(s))
|
||||||
local line = string.match(msg, ":(%d+):")
|
local line = string.match(msg, ":(%d+):")
|
||||||
assert((line and line+0) == l)
|
assert(tonumber(line) == l)
|
||||||
end
|
end
|
||||||
|
|
||||||
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
|
lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
|
||||||
@ -350,6 +350,23 @@ X=1;lineerror((p), 2)
|
|||||||
X=2;lineerror((p), 1)
|
X=2;lineerror((p), 1)
|
||||||
|
|
||||||
|
|
||||||
|
lineerror([[
|
||||||
|
local b = false
|
||||||
|
if not b then
|
||||||
|
error 'test'
|
||||||
|
end]], 3)
|
||||||
|
|
||||||
|
lineerror([[
|
||||||
|
local b = false
|
||||||
|
if not b then
|
||||||
|
if not b then
|
||||||
|
if not b then
|
||||||
|
error 'test'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end]], 5)
|
||||||
|
|
||||||
|
|
||||||
if not _soft then
|
if not _soft then
|
||||||
-- several tests that exaust the Lua stack
|
-- several tests that exaust the Lua stack
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
|
Loading…
Reference in New Issue
Block a user