From a6879cb3982f02744dd77b6663ae6bc14162e652 Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Sat, 19 Dec 2015 10:43:32 -0800
Subject: [PATCH 02/13] Makefile: ensure we always install the symlink for
"luajit".
---
Makefile | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/Makefile b/Makefile
index 923bf72b..f4b84081 100644
--- a/Makefile
+++ b/Makefile
@@ -130,13 +130,8 @@ install: $(LUAJIT_BIN)
$(RM) $(FILE_PC).tmp
cd src && $(INSTALL_F) $(FILES_INC) $(INSTALL_INC)
cd src/jit && $(INSTALL_F) $(FILES_JITLIB) $(INSTALL_JITLIB)
+ $(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)
@echo "==== Successfully installed LuaJIT $(VERSION) to $(PREFIX) ===="
- @echo ""
- @echo "Note: the development releases deliberately do NOT install a symlink for luajit"
- @echo "You can do this now by running this command (with sudo):"
- @echo ""
- @echo " $(SYMLINK) $(INSTALL_TNAME) $(INSTALL_TSYM)"
- @echo ""
uninstall:
--
2.21.0
From e29e78dd64573947777e8ca7741d46d1c0ba2f7b Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Tue, 14 Mar 2017 14:26:48 -0700
Subject: [PATCH 03/13] optimize: lj_str_new: tests the full hash value before
doing the full string comparison on hash collisions. thanks Shuxin Yang for
the patch.
---
src/lj_str.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lj_str.c b/src/lj_str.c
index 264dedc1..f1b5fb5d 100644
--- a/src/lj_str.c
+++ b/src/lj_str.c
@@ -152,7 +152,7 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) {
while (o != NULL) {
GCstr *sx = gco2str(o);
- if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) {
+ if (sx->len == len && sx->hash == h && str_fastcmp(str, strdata(sx), len) == 0) {
/* Resurrect if dead. Can only happen with fixstring() (keywords). */
if (isdead(g, o)) flipwhite(o);
return sx; /* Return existing string. */
@@ -162,7 +162,7 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
} else { /* Slow path: end of string is too close to a page boundary. */
while (o != NULL) {
GCstr *sx = gco2str(o);
- if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
+ if (sx->len == len && sx->hash == h && memcmp(str, strdata(sx), len) == 0) {
/* Resurrect if dead. Can only happen with fixstring() (keywords). */
if (isdead(g, o)) flipwhite(o);
return sx; /* Return existing string. */
--
2.21.0
From 555ee4e814f799937ca505423fc05c0b0402f81c Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <yichun@openresty.com>
Date: Tue, 15 Jan 2019 12:17:50 -0800
Subject: [PATCH 04/13] bugfix: fixed assertion failure "lj_record.c:92:
rec_check_slots: Assertion `nslots <= 250' failed" found by stressing our
edgelang compiler.
---
src/lj_record.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/lj_record.c b/src/lj_record.c
index 7f37d6c6..4a50de1b 100644
--- a/src/lj_record.c
+++ b/src/lj_record.c
@@ -1860,6 +1860,8 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
lj_trace_err_info(J, LJ_TRERR_NYIBC);
}
}
+ if (J->baseslot + J->maxslot >= LJ_MAX_JSLOTS)
+ lj_trace_err(J, LJ_TRERR_STACKOV);
}
/* -- Record allocations -------------------------------------------------- */
--
2.21.0
From 58e9941b6268202f7953a5534e0c662ad90b2510 Mon Sep 17 00:00:00 2001
From: doujiang24 <doujiang24@gmail.com>
Date: Sun, 12 Mar 2017 21:04:50 +0800
Subject: [PATCH 05/13] feature: added the bytecode option `L` to display lua
source line numbers.
Signed-off-by: Yichun Zhang (agentzh) <agentzh@gmail.com>
---
src/jit/bc.lua | 20 +++++++++++++-------
src/jit/bcsave.lua | 11 ++++++++---
src/lib_jit.c | 6 ++++++
3 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/src/jit/bc.lua b/src/jit/bc.lua
index 193cf01f..80f92689 100644
--- a/src/jit/bc.lua
+++ b/src/jit/bc.lua
@@ -63,15 +63,21 @@ local function ctlsub(c)
end
-- Return one bytecode line.
-local function bcline(func, pc, prefix)
- local ins, m = funcbc(func, pc)
+local function bcline(func, pc, prefix, lineinfo)
+ local ins, m, l = funcbc(func, pc, lineinfo and 1 or 0)
if not ins then return end
local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
local a = band(shr(ins, 8), 0xff)
local oidx = 6*band(ins, 0xff)
local op = sub(bcnames, oidx+1, oidx+6)
- local s = format("%04d %s %-6s %3s ",
- pc, prefix or " ", op, ma == 0 and "" or a)
+ local s
+ if lineinfo then
+ s = format("%04d %7s %s %-6s %3s ",
+ pc, "["..l.."]", prefix or " ", op, ma == 0 and "" or a)
+ else
+ s = format("%04d %s %-6s %3s ",
+ pc, prefix or " ", op, ma == 0 and "" or a)
+ end
local d = shr(ins, 16)
if mc == 13*128 then -- BCMjump
return format("%s=> %04d\n", s, pc+d-0x7fff)
@@ -124,20 +130,20 @@ local function bctargets(func)
end
-- Dump bytecode instructions of a function.
-local function bcdump(func, out, all)
+local function bcdump(func, out, all, lineinfo)
if not out then out = stdout end
local fi = funcinfo(func)
if all and fi.children then
for n=-1,-1000000000,-1 do
local k = funck(func, n)
if not k then break end
- if type(k) == "proto" then bcdump(k, out, true) end
+ if type(k) == "proto" then bcdump(k, out, true, lineinfo) end
end
end
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
local target = bctargets(func)
for pc=1,1000000000 do
- local s = bcline(func, pc, target[pc] and "=>")
+ local s = bcline(func, pc, target[pc] and "=>", lineinfo)
if not s then break end
out:write(s)
end
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index 2553d97e..9c6146c2 100644
--- a/src/jit/bcsave.lua
+++ b/src/jit/bcsave.lua
@@ -23,6 +23,7 @@ local function usage()
io.stderr:write[[
Save LuaJIT bytecode: luajit -b[options] input output
-l Only list bytecode.
+ -L Only list bytecode with lineinfo.
-s Strip debug info (default).
-g Keep debug info.
-n name Set module name (default: auto-detect from input name).
@@ -575,9 +576,9 @@ end
------------------------------------------------------------------------------
-local function bclist(input, output)
+local function bclist(input, output, lineinfo)
local f = readfile(input)
- require("jit.bc").dump(f, savefile(output, "w"), true)
+ require("jit.bc").dump(f, savefile(output, "w"), true, lineinfo)
end
local function bcsave(ctx, input, output)
@@ -604,6 +605,7 @@ local function docmd(...)
local arg = {...}
local n = 1
local list = false
+ local lineinfo = false
local ctx = {
strip = true, arch = jit.arch, os = string.lower(jit.os),
type = false, modname = false,
@@ -617,6 +619,9 @@ local function docmd(...)
local opt = string.sub(a, m, m)
if opt == "l" then
list = true
+ elseif opt == "L" then
+ list = true
+ lineinfo = true
elseif opt == "s" then
ctx.strip = true
elseif opt == "g" then
@@ -645,7 +650,7 @@ local function docmd(...)
end
if list then
if #arg == 0 or #arg > 2 then usage() end
- bclist(arg[1], arg[2] or "-")
+ bclist(arg[1], arg[2] or "-", lineinfo)
else
if #arg ~= 2 then usage() end
bcsave(ctx, arg[1], arg[2])
diff --git a/src/lib_jit.c b/src/lib_jit.c
index 6e265fdb..6972550b 100644
--- a/src/lib_jit.c
+++ b/src/lib_jit.c
@@ -224,6 +224,7 @@ LJLIB_CF(jit_util_funcbc)
{
GCproto *pt = check_Lproto(L, 0);
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
+ int lineinfo = lj_lib_optint(L, 3, 0);
if (pc < pt->sizebc) {
BCIns ins = proto_bc(pt)[pc];
BCOp op = bc_op(ins);
@@ -231,6 +232,11 @@ LJLIB_CF(jit_util_funcbc)
setintV(L->top, ins);
setintV(L->top+1, lj_bc_mode[op]);
L->top += 2;
+ if (lineinfo) {
+ setintV(L->top, lj_debug_line(pt, pc));
+ L->top += 1;
+ return 3;
+ }
return 2;
}
return 0;
--
2.21.0
From a61c93d0784c532db4ec0797475a0e0ad93dda4c Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <yichun@openresty.com>
Date: Wed, 27 Feb 2019 17:20:19 -0800
Subject: [PATCH 06/13] bugfix: ffi.C.FUNC(): it lacked a write barrier which
might lead to use-after-free issues and memory corruptions.
Fix #42.
---
src/lj_clib.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/lj_clib.c b/src/lj_clib.c
index f016b06b..a8672052 100644
--- a/src/lj_clib.c
+++ b/src/lj_clib.c
@@ -384,6 +384,7 @@ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
cd = lj_cdata_new(cts, id, CTSIZE_PTR);
*(void **)cdataptr(cd) = p;
setcdataV(L, tv, cd);
+ lj_gc_anybarriert(L, cl->cache);
}
}
return tv;
--
2.21.0
From 3086b483e76ad12ae0a0dfab60960c1175b69dab Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Thu, 15 May 2014 16:03:29 -0700
Subject: [PATCH 07/13] feature: added internal memory-buffer-based trace
entry/exit/start-recording event logging, mainly for debugging bugs in the
JIT compiler. it requires -DLUA_USE_TRACE_LOGS when building.
---
src/lj_debug.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
src/lj_debug.h | 11 +++++
src/lj_trace.c | 9 ++++
src/vm_x86.dasc | 24 ++++++++++
4 files changed, 169 insertions(+)
diff --git a/src/lj_debug.c b/src/lj_debug.c
index 959dc289..7f4f793a 100644
--- a/src/lj_debug.c
+++ b/src/lj_debug.c
@@ -697,3 +697,128 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
lua_concat(L, (int)(L->top - L->base) - top);
}
+#ifdef LUA_USE_TRACE_LOGS
+
+#include "lj_dispatch.h"
+
+#define MAX_TRACE_EVENTS 64
+
+enum {
+ LJ_TRACE_EVENT_ENTER,
+ LJ_TRACE_EVENT_EXIT,
+ LJ_TRACE_EVENT_START
+};
+
+typedef struct {
+ int event;
+ unsigned traceno;
+ unsigned exitno;
+ int directexit;
+ const BCIns *ins;
+ lua_State *thread;
+ GCfunc *fn;
+} lj_trace_event_record_t;
+
+static lj_trace_event_record_t lj_trace_events[MAX_TRACE_EVENTS];
+
+static int rb_start = 0;
+static int rb_end = 0;
+static int rb_full = 0;
+
+static void
+lj_trace_log_event(lj_trace_event_record_t *rec)
+{
+ lj_trace_events[rb_end] = *rec;
+
+ if (rb_full) {
+ rb_end++;
+ if (rb_end == MAX_TRACE_EVENTS) {
+ rb_end = 0;
+ }
+ rb_start = rb_end;
+
+ } else {
+ rb_end++;
+ if (rb_end == MAX_TRACE_EVENTS) {
+ rb_end = 0;
+ rb_full = MAX_TRACE_EVENTS;
+ }
+ }
+}
+
+static GCfunc*
+lj_debug_top_frame_fn(lua_State *L, const BCIns *pc)
+{
+ int size;
+ cTValue *frame;
+
+ frame = lj_debug_frame(L, 0, &size);
+ if (frame == NULL) {
+ return NULL;
+ }
+
+ return frame_func(frame);
+}
+
+void
+lj_log_trace_start_record(lua_State *L, unsigned traceno, const BCIns *pc,
+ GCfunc *fn)
+{
+ lj_trace_event_record_t r;
+
+ r.event = LJ_TRACE_EVENT_START;
+ r.thread = L;
+ r.ins = pc;
+ r.traceno = traceno;
+ r.fn = fn;
+
+ lj_trace_log_event(&r);
+}
+
+void
+lj_log_trace_entry(lua_State *L, unsigned traceno, const BCIns *pc)
+{
+ lj_trace_event_record_t r;
+
+ r.event = LJ_TRACE_EVENT_ENTER;
+ r.thread = L;
+ r.ins = pc;
+ r.traceno = traceno;
+ r.fn = lj_debug_top_frame_fn(L, pc);
+
+ lj_trace_log_event(&r);
+}
+
+static void
+lj_log_trace_exit_helper(lua_State *L, int vmstate, const BCIns *pc, int direct)
+{
+ if (vmstate >= 0) {
+ lj_trace_event_record_t r;
+
+ jit_State *J = L2J(L);
+
+ r.event = LJ_TRACE_EVENT_EXIT;
+ r.thread = L;
+ r.ins = pc;
+ r.traceno = vmstate;
+ r.exitno = J->exitno;
+ r.directexit = direct;
+ r.fn = lj_debug_top_frame_fn(L, pc);
+
+ lj_trace_log_event(&r);
+ }
+}
+
+void
+lj_log_trace_normal_exit(lua_State *L, int vmstate, const BCIns *pc)
+{
+ lj_log_trace_exit_helper(L, vmstate, pc, 0);
+}
+
+void
+lj_log_trace_direct_exit(lua_State *L, int vmstate, const BCIns *pc)
+{
+ lj_log_trace_exit_helper(L, vmstate, pc, 1);
+}
+
+#endif /* LUA_USE_TRACE_LOGS */
diff --git a/src/lj_debug.h b/src/lj_debug.h
index 5917c00b..82f53bda 100644
--- a/src/lj_debug.h
+++ b/src/lj_debug.h
@@ -62,4 +62,15 @@ enum {
VARNAME__MAX
};
+#ifdef LUA_USE_TRACE_LOGS
+LJ_FUNC void LJ_FASTCALL lj_log_trace_direct_exit(lua_State *L,
+ int vmstate, const BCIns *pc);
+LJ_FUNC void LJ_FASTCALL lj_log_trace_normal_exit(lua_State *L,
+ int vmstate, const BCIns *pc);
+LJ_FUNC void LJ_FASTCALL lj_log_trace_entry(lua_State *L,
+ unsigned traceno, const BCIns *pc);
+LJ_FUNC void LJ_FASTCALL lj_log_trace_start_record(lua_State *L, unsigned traceno,
+ const BCIns *pc, GCfunc *fn);
+#endif
+
#endif
diff --git a/src/lj_trace.c b/src/lj_trace.c
index d85b47f8..c2f0d8cf 100644
--- a/src/lj_trace.c
+++ b/src/lj_trace.c
@@ -404,6 +404,9 @@ static void trace_start(jit_State *J)
{
lua_State *L;
TraceNo traceno;
+#ifdef LUA_USE_TRACE_LOGS
+ const BCIns *pc = J->pc;
+#endif
if ((J->pt->flags & PROTO_NOJIT)) { /* JIT disabled for this proto? */
if (J->parent == 0 && J->exitno == 0) {
@@ -462,6 +465,9 @@ static void trace_start(jit_State *J)
}
);
lj_record_setup(J);
+#ifdef LUA_USE_TRACE_LOGS
+ lj_log_trace_start_record(L, (unsigned) J->cur.traceno, pc, J->fn);
+#endif
}
/* Stop tracing. */
@@ -890,6 +896,9 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
}
}
}
+#ifdef LUA_USE_TRACE_LOGS
+ lj_log_trace_normal_exit(L, (int) T->traceno, pc);
+#endif
/* Return MULTRES or 0. */
ERRNO_RESTORE
switch (bc_op(*pc)) {
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc
index 211ae7b9..66377cd5 100644
--- a/src/vm_x86.dasc
+++ b/src/vm_x86.dasc
@@ -2919,6 +2919,19 @@ static void build_subroutines(BuildCtx *ctx)
| mov r13, TMPa
| mov r12, TMPQ
|.endif
+#ifdef LUA_USE_TRACE_LOGS
+ | mov FCARG1, SAVE_L
+ | mov L:FCARG1->base, BASE
+ | mov RB, RD // Save RD
+ | mov TMP1, PC // Save PC
+ | mov CARG3d, PC // CARG3d == BASE
+ | mov FCARG2, dword [DISPATCH+DISPATCH_GL(vmstate)]
+ | call extern lj_log_trace_direct_exit@8
+ | mov PC, TMP1
+ | mov RD, RB
+ | mov RB, SAVE_L
+ | mov BASE, L:RB->base
+#endif
| test RD, RD; js >9 // Check for error from exit.
| mov L:RB, SAVE_L
| mov MULTRES, RD
@@ -5260,6 +5273,17 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
case BC_JLOOP:
|.if JIT
| ins_AD // RA = base (ignored), RD = traceno
+#ifdef LUA_USE_TRACE_LOGS
+ | mov L:RB, SAVE_L
+ | mov L:RB->base, BASE // Save BASE
+ | mov TMP1, RD // Save RD
+ | mov CARG3d, PC // CARG3d == BASE
+ | mov FCARG2, RD
+ | mov FCARG1, RB
+ | call extern lj_log_trace_entry@8
+ | mov RD, TMP1
+ | mov BASE, L:RB->base
+#endif
| mov RA, [DISPATCH+DISPATCH_J(trace)]
| mov TRACE:RD, [RA+RD*4]
| mov RDa, TRACE:RD->mcode
--
2.21.0
From 00a5957d632f1715fdc88c1a3fe7cc355f5a13cb Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Wed, 21 May 2014 16:05:13 -0700
Subject: [PATCH 08/13] bugfix: fixed build regression on i386 introduced by
the LUA_USE_TRACE_LOGS feature.
---
src/vm_x86.dasc | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc
index 66377cd5..50210010 100644
--- a/src/vm_x86.dasc
+++ b/src/vm_x86.dasc
@@ -2920,6 +2920,7 @@ static void build_subroutines(BuildCtx *ctx)
| mov r12, TMPQ
|.endif
#ifdef LUA_USE_TRACE_LOGS
+ |.if X64
| mov FCARG1, SAVE_L
| mov L:FCARG1->base, BASE
| mov RB, RD // Save RD
@@ -2931,6 +2932,7 @@ static void build_subroutines(BuildCtx *ctx)
| mov RD, RB
| mov RB, SAVE_L
| mov BASE, L:RB->base
+ |.endif
#endif
| test RD, RD; js >9 // Check for error from exit.
| mov L:RB, SAVE_L
@@ -5274,6 +5276,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
|.if JIT
| ins_AD // RA = base (ignored), RD = traceno
#ifdef LUA_USE_TRACE_LOGS
+ |.if X64
| mov L:RB, SAVE_L
| mov L:RB->base, BASE // Save BASE
| mov TMP1, RD // Save RD
@@ -5283,6 +5286,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| call extern lj_log_trace_entry@8
| mov RD, TMP1
| mov BASE, L:RB->base
+ |.endif
#endif
| mov RA, [DISPATCH+DISPATCH_J(trace)]
| mov TRACE:RD, [RA+RD*4]
--
2.21.0
From 7950afe36eadad8b529f4aa90b303861619a2322 Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Sat, 7 Jun 2014 13:41:24 -0700
Subject: [PATCH 09/13] fixed compilation errors on Solaris when
-DLUA_USE_TRACE_LOGS is enabled.
---
src/lj_debug.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/lj_debug.c b/src/lj_debug.c
index 7f4f793a..b93b69d3 100644
--- a/src/lj_debug.c
+++ b/src/lj_debug.c
@@ -760,7 +760,7 @@ lj_debug_top_frame_fn(lua_State *L, const BCIns *pc)
return frame_func(frame);
}
-void
+LJ_FUNC void LJ_FASTCALL
lj_log_trace_start_record(lua_State *L, unsigned traceno, const BCIns *pc,
GCfunc *fn)
{
@@ -775,7 +775,7 @@ lj_log_trace_start_record(lua_State *L, unsigned traceno, const BCIns *pc,
lj_trace_log_event(&r);
}
-void
+LJ_FUNC void LJ_FASTCALL
lj_log_trace_entry(lua_State *L, unsigned traceno, const BCIns *pc)
{
lj_trace_event_record_t r;
@@ -809,13 +809,13 @@ lj_log_trace_exit_helper(lua_State *L, int vmstate, const BCIns *pc, int direct)
}
}
-void
+LJ_FUNC void LJ_FASTCALL
lj_log_trace_normal_exit(lua_State *L, int vmstate, const BCIns *pc)
{
lj_log_trace_exit_helper(L, vmstate, pc, 0);
}
-void
+LJ_FUNC void LJ_FASTCALL
lj_log_trace_direct_exit(lua_State *L, int vmstate, const BCIns *pc)
{
lj_log_trace_exit_helper(L, vmstate, pc, 1);
--
2.21.0
From bd304a366be2ffb10eec6aeba390595232958320 Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <agentzh@gmail.com>
Date: Tue, 27 May 2014 12:37:13 -0700
Subject: [PATCH 10/13] feature: jit.dump: output Lua source location after
every BC.
---
src/jit/dump.lua | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/jit/dump.lua b/src/jit/dump.lua
index 2bea652b..ef0dca61 100644
--- a/src/jit/dump.lua
+++ b/src/jit/dump.lua
@@ -591,6 +591,9 @@ local function dump_record(tr, func, pc, depth, callee)
if pc >= 0 then
line = bcline(func, pc, recprefix)
if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
+ if pc > 0 then
+ line = sub(line, 1, -2) .. " (" .. fmtfunc(func, pc) .. ")\n"
+ end
else
line = "0000 "..recprefix.." FUNCC \n"
callee = func
--
2.21.0
From cce112ca4fdde7d1ca5963c50d0621fb2e526524 Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <yichun@openresty.com>
Date: Fri, 5 Apr 2019 12:38:40 -0700
Subject: [PATCH 11/13] feature: luajit -bl: dump the constant tables (KGC and
KN) for each lua proto object as well.
---
src/jit/bc.lua | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/src/jit/bc.lua b/src/jit/bc.lua
index 80f92689..9fee4cda 100644
--- a/src/jit/bc.lua
+++ b/src/jit/bc.lua
@@ -141,6 +141,38 @@ local function bcdump(func, out, all, lineinfo)
end
end
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
+
+ for n=-1,-1000000000,-1 do
+ local kc = funck(func, n)
+ if not kc then break end
+
+ local typ = type(kc)
+ if typ == "string" then
+ kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
+ out:write(format("KGC %d %s\n", -(n + 1), kc))
+ elseif typ == "proto" then
+ local fi = funcinfo(kc)
+ if fi.ffid then
+ kc = vmdef.ffnames[fi.ffid]
+ else
+ kc = fi.loc
+ end
+ out:write(format("KGC %d %s\n", -(n + 1), kc))
+ elseif typ == "table" then
+ out:write(format("KGC %d table\n", -(n + 1)))
+ else
+ -- error("unknown KGC type: " .. typ)
+ end
+ end
+
+ for n=1,1000000000 do
+ local kc = funck(func, n)
+ if not kc then break end
+ if type(kc) == "number" then
+ out:write(format("KN %d %s\n", n, kc))
+ end
+ end
+
local target = bctargets(func)
for pc=1,1000000000 do
local s = bcline(func, pc, target[pc] and "=>", lineinfo)
--
2.21.0
From 7d5f5be581ed392059601168a95068e026765aa0 Mon Sep 17 00:00:00 2001
From: "Yichun Zhang (agentzh)" <yichun@openresty.com>
Date: Fri, 17 May 2019 14:49:48 -0700
Subject: [PATCH 13/13] bugfix: thanks Julien Desgats for the report and Peter
Cawley for the patch.
The test covering this bug was submitted to the openresty/luajit2-test-suite
repo as commit ce2c916d55.
---
src/lj_tab.c | 81 ++++++++++++++++++++++++++++++++++------------------
1 file changed, 53 insertions(+), 28 deletions(-)
diff --git a/src/lj_tab.c b/src/lj_tab.c
index c51666d3..ff216f3c 100644
--- a/src/lj_tab.c
+++ b/src/lj_tab.c
@@ -474,6 +474,7 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key)
lua_assert(freenode != &G(L)->nilnode);
collide = hashkey(t, &n->key);
if (collide != n) { /* Colliding node not the main node? */
+ Node *nn;
while (noderef(collide->next) != n) /* Find predecessor. */
collide = nextnode(collide);
setmref(collide->next, freenode); /* Relink chain. */
@@ -483,39 +484,63 @@ TValue *lj_tab_newkey(lua_State *L, GCtab *t, cTValue *key)
freenode->next = n->next;
setmref(n->next, NULL);
setnilV(&n->val);
- /* Rechain pseudo-resurrected string keys with colliding hashes. */
- while (nextnode(freenode)) {
- Node *nn = nextnode(freenode);
- if (tvisstr(&nn->key) && !tvisnil(&nn->val) &&
- hashstr(t, strV(&nn->key)) == n) {
- freenode->next = nn->next;
- nn->next = n->next;
- setmref(n->next, nn);
- /*
- ** Rechaining a resurrected string key creates a new dilemma:
- ** Another string key may have originally been resurrected via
- ** _any_ of the previous nodes as a chain anchor. Including
- ** a node that had to be moved, which makes them unreachable.
- ** It's not feasible to check for all previous nodes, so rechain
- ** any string key that's currently in a non-main positions.
- */
- while ((nn = nextnode(freenode))) {
- if (tvisstr(&nn->key) && !tvisnil(&nn->val)) {
- Node *mn = hashstr(t, strV(&nn->key));
- if (mn != freenode) {
- freenode->next = nn->next;
- nn->next = mn->next;
- setmref(mn->next, nn);
+ /*
+ ** Nodes after n might have n as their main node, and need rechaining
+ ** back onto n. We make use of the following property of tables: for all
+ ** nodes m, at least one of the following four statements is true:
+ ** 1. tvisnil(&m->key) NB: tvisnil(&m->val) is a stronger statement
+ ** 2. tvisstr(&m->key)
+ ** 3. tvisstr(&main(m)->key)
+ ** 4. main(m) == main(main(m))
+ ** Initially, we need to rechain any nn which has main(nn) == n. As
+ ** main(n) != n (because collide != n earlier), main(nn) == n requires
+ ** either statement 2 or statement 3 to be true about nn.
+ */
+ if (!tvisstr(&n->key)) {
+ /* Statement 3 is not true, so only need to consider string keys. */
+ while ((nn = nextnode(freenode))) {
+ if (tvisstr(&nn->key) && !tvisnil(&nn->val) &&
+ hashstr(t, strV(&nn->key)) == n) {
+ goto rechain;
+ }
+ freenode = nn;
+ }
+ } else {
+ /* Statement 3 is true, so need to consider all types of key. */
+ while ((nn = nextnode(freenode))) {
+ if (!tvisnil(&nn->val) && hashkey(t, &nn->key) == n) {
+ rechain:
+ freenode->next = nn->next;
+ nn->next = n->next;
+ setmref(n->next, nn);
+ /*
+ ** Rechaining one node onto n creates a new dilemma: we now need
+ ** to rechain any nn which has main(nn) == n OR has main(nn) equal
+ ** to any node which has already been rechained. Furthermore, at
+ ** least one of n and n->next will have a string key, so all types
+ ** of nn key need to be considered. Rather than testing whether
+ ** main(nn) definitely _is_ in the new chain, we test whether it
+ ** might _not_ be in the old chain, and if so re-link it into
+ ** the correct chain.
+ */
+ while ((nn = nextnode(freenode))) {
+ if (!tvisnil(&nn->val)) {
+ Node *mn = hashkey(t, &nn->key);
+ if (mn != freenode && mn != nn) {
+ freenode->next = nn->next;
+ nn->next = mn->next;
+ setmref(mn->next, nn);
+ } else {
+ freenode = nn;
+ }
} else {
freenode = nn;
}
- } else {
- freenode = nn;
}
+ break;
+ } else {
+ freenode = nn;
}
- break;
- } else {
- freenode = nn;
}
}
} else { /* Otherwise use free node. */
--
2.21.0