From 88ed9fdbbba632d174a473a0a97c914089c2916d Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 10 Mar 2024 17:13:28 +0100 Subject: [PATCH 01/15] Handle stack reallocation in debug.setmetatable() and lua_setmetatable(). Thanks to Sergey Kaplun. #1172 --- src/lj_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lj_api.c b/src/lj_api.c index 2018cb8f..d40ade30 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -975,6 +975,7 @@ LUA_API int lua_setmetatable(lua_State *L, int idx) /* Flush cache, since traces specialize to basemt. But not during __gc. */ if (lj_trace_flushall(L)) lj_err_caller(L, LJ_ERR_NOGCMM); + o = index2adr(L, idx); /* Stack may have been reallocated. */ if (tvisbool(o)) { /* NOBARRIER: basemt is a GC root. */ setgcref(basemt_it(g, LJ_TTRUE), obj2gco(mt)); From dda1ac273ad946387088d91039a8ae319359903d Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 10 Mar 2024 17:16:41 +0100 Subject: [PATCH 02/15] FFI: Treat cdata finalizer table as a GC root. Thanks to Sergey Bronnikov. #1168 --- src/lj_gc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lj_gc.c b/src/lj_gc.c index 06484f6f..9c0d6797 100644 --- a/src/lj_gc.c +++ b/src/lj_gc.c @@ -93,6 +93,9 @@ static void gc_mark_start(global_State *g) gc_markobj(g, tabref(mainthread(g)->env)); gc_marktv(g, &g->registrytv); gc_mark_gcroot(g); +#if LJ_HASFFI + if (ctype_ctsG(g)) gc_markobj(g, ctype_ctsG(g)->finalizer); +#endif g->gc.state = GCSpropagate; } From 302366a33853b730f1b7eb61d792abc4f84f0caa Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 10 Mar 2024 17:19:29 +0100 Subject: [PATCH 03/15] Check frame size limit before returning to a lower frame. Thanks to Sergey Kaplun. #1173 --- src/lj_record.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lj_record.c b/src/lj_record.c index 0122105b..35e6d6e1 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -749,6 +749,8 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) lj_trace_err(J, LJ_TRERR_LLEAVE); } else if (J->needsnap) { /* Tailcalled to ff with side-effects. */ lj_trace_err(J, LJ_TRERR_NYIRETL); /* No way to insert snapshot here. */ + } else if (1 + pt->framesize >= LJ_MAX_JSLOTS) { + lj_trace_err(J, LJ_TRERR_STACKOV); } else { /* Return to lower frame. Guard for the target we return to. */ TRef trpt = lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); TRef trpc = lj_ir_kptr(J, (void *)frame_pc(frame)); From cae361187e7e1e3545353fb560c032cdace32d5f Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 10 Mar 2024 17:23:21 +0100 Subject: [PATCH 04/15] Prevent down-recursion for side traces. Thanks to Sergey Kaplun. #1169 --- src/lj_record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lj_record.c b/src/lj_record.c index 35e6d6e1..f2a06f41 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -728,7 +728,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) if ((pt->flags & PROTO_NOJIT)) lj_trace_err(J, LJ_TRERR_CJITOFF); if (J->framedepth == 0 && J->pt && frame == J->L->base - 1) { - if (check_downrec_unroll(J, pt)) { + if (!J->cur.root && check_downrec_unroll(J, pt)) { J->maxslot = (BCReg)(rbase + gotresults); lj_snap_purge(J); rec_stop(J, LJ_TRLINK_DOWNREC, J->cur.traceno); /* Down-recursion. */ From bcc5125a9188179d23c223b8865ed94951fb91b3 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 10 Mar 2024 17:26:36 +0100 Subject: [PATCH 05/15] Fix recording of __concat metamethod. Thanks to Sergey Kaplun. #1164 --- src/lj_record.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lj_record.c b/src/lj_record.c index a9092d92..48bbbb20 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -903,6 +903,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) { TValue *frame = J->L->base - 1; ptrdiff_t i; + BCReg baseadj = 0; for (i = 0; i < gotresults; i++) (void)getslot(J, rbase+i); /* Ensure all results have a reference. */ while (frame_ispcall(frame)) { /* Immediately resolve pcall() returns. */ @@ -911,6 +912,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) lj_trace_err(J, LJ_TRERR_NYIRETL); lj_assertJ(J->baseslot > 1+LJ_FR2, "bad baseslot for return"); gotresults++; + baseadj += cbase; rbase += cbase; J->baseslot -= (BCReg)cbase; J->base -= cbase; @@ -935,6 +937,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) if (--J->framedepth < 0) /* NYI: return of vararg func to lower frame. */ lj_trace_err(J, LJ_TRERR_NYIRETL); lj_assertJ(J->baseslot > 1+LJ_FR2, "bad baseslot for return"); + baseadj += cbase; rbase += cbase; J->baseslot -= (BCReg)cbase; J->base -= cbase; @@ -1005,7 +1008,8 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) BCReg bslot = bc_b(*(frame_contpc(frame)-1)); TRef tr = gotresults ? J->base[cbase+rbase] : TREF_NIL; if (bslot != J->maxslot) { /* Concatenate the remainder. */ - TValue *b = J->L->base, save; /* Simulate lower frame and result. */ + /* Simulate lower frame and result. */ + TValue *b = J->L->base - baseadj, save; /* Can't handle MM_concat + CALLT + fast func side-effects. */ if (J->postproc != LJ_POST_NONE) lj_trace_err(J, LJ_TRERR_NYIRETL); @@ -1018,7 +1022,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) J->L->base = b - cbase; tr = rec_cat(J, bslot, cbase-(2<L->base + cbase; /* Undo. */ - J->L->base = b; + J->L->base = b + baseadj; copyTV(J->L, b-(2< Date: Sun, 10 Mar 2024 17:29:48 +0100 Subject: [PATCH 06/15] Handle all types of errors during trace stitching. Thanks to Sergey Kaplun and Peter Cawley. #1166 #720 --- src/lj_ffrecord.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 30dc6bfc..03d0e6ec 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -98,6 +98,14 @@ static ptrdiff_t results_wanted(jit_State *J) return -1; } +static TValue *rec_stop_stitch_cp(lua_State *L, lua_CFunction dummy, void *ud) +{ + jit_State *J = (jit_State *)ud; + lj_record_stop(J, LJ_TRLINK_STITCH, 0); + UNUSED(L); UNUSED(dummy); + return NULL; +} + /* Trace stitching: add continuation below frame to start a new trace. */ static void recff_stitch(jit_State *J) { @@ -108,10 +116,7 @@ static void recff_stitch(jit_State *J) TValue *nframe = base + 1 + LJ_FR2; const BCIns *pc = frame_pc(base-1); TValue *pframe = frame_prevl(base-1); - - /* Check for this now. Throwing in lj_record_stop messes up the stack. */ - if (J->cur.nsnap >= (MSize)J->param[JIT_P_maxsnap]) - lj_trace_err(J, LJ_TRERR_SNAPOV); + int errcode; /* Move func + args up in Lua stack and insert continuation. */ memmove(&base[1], &base[-1-LJ_FR2], sizeof(TValue)*nslot); @@ -136,13 +141,19 @@ static void recff_stitch(jit_State *J) J->baseslot += 2 + LJ_FR2; J->framedepth++; - lj_record_stop(J, LJ_TRLINK_STITCH, 0); + errcode = lj_vm_cpcall(L, NULL, J, rec_stop_stitch_cp); /* Undo Lua stack changes. */ memmove(&base[-1-LJ_FR2], &base[1], sizeof(TValue)*nslot); setframe_pc(base-1, pc); L->base -= 2 + LJ_FR2; L->top -= 2 + LJ_FR2; + + if (errcode) { + if (errcode == LUA_ERRRUN) + copyTV(L, L->top-1, L->top + (1 + LJ_FR2)); + lj_err_throw(L, errcode); /* Propagate errors. */ + } } /* Fallback handler for fast functions that are not recorded (yet). */ From 243b7682a521324c7891090acfc3011ab17dcb18 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 18 Apr 2024 23:49:43 +0200 Subject: [PATCH 07/15] Fix serialization format docs. Reported by nounwind. --- doc/ext_buffer.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ext_buffer.html b/doc/ext_buffer.html index bfaa24cb..61f425f1 100644 --- a/doc/ext_buffer.html +++ b/doc/ext_buffer.html @@ -588,9 +588,9 @@ num → 0x07 double.L tab → 0x08 // Empty table | 0x09 h.U h*{object object} // Key/value hash | 0x0a a.U a*object // 0-based array - | 0x0b a.U a*object h.U h*{object object} // Mixed + | 0x0b a.U h.U a*object h*{object object} // Mixed | 0x0c a.U (a-1)*object // 1-based array - | 0x0d a.U (a-1)*object h.U h*{object object} // Mixed + | 0x0d a.U h.U (a-1)*object h*{object object} // Mixed tab_mt → 0x0e (index-1).U tab // Metatable dict entry int64 → 0x10 int.L // FFI int64_t From b8b49bf3954b23e32e34187a6ada00021c26e172 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 18 Apr 2024 23:57:53 +0200 Subject: [PATCH 08/15] Use generic trace error for OOM during trace stitching. Thanks to Sergey Kaplun. #1166 --- src/lj_ffrecord.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 03d0e6ec..923824d9 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -152,6 +152,8 @@ static void recff_stitch(jit_State *J) if (errcode) { if (errcode == LUA_ERRRUN) copyTV(L, L->top-1, L->top + (1 + LJ_FR2)); + else + setintV(L->top-1, (int32_t)LJ_TRERR_RECERR); lj_err_throw(L, errcode); /* Propagate errors. */ } } From d2fe2a6d465a3e4c74c9876db94ae606f9c6983b Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 00:12:22 +0200 Subject: [PATCH 09/15] Show name of NYI bytecode in -jv and -jdump. Suggested by Sergey Kaplun. #1176 #567 --- src/jit/dump.lua | 7 ++++++- src/jit/v.lua | 9 +++++++-- src/lj_traceerr.h | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/jit/dump.lua b/src/jit/dump.lua index 746732f9..f296a517 100644 --- a/src/jit/dump.lua +++ b/src/jit/dump.lua @@ -552,7 +552,12 @@ local recdepth = 0 local function fmterr(err, info) if type(err) == "number" then if type(info) == "function" then info = fmtfunc(info) end - err = format(vmdef.traceerr[err], info) + local fmt = vmdef.traceerr[err] + if fmt == "NYI: bytecode %s" then + local oidx = 6 * info + info = sub(vmdef.bcnames, oidx+1, oidx+6) + end + err = format(fmt, info) end return err end diff --git a/src/jit/v.lua b/src/jit/v.lua index 8e91f494..45a663d7 100644 --- a/src/jit/v.lua +++ b/src/jit/v.lua @@ -62,7 +62,7 @@ local jit = require("jit") local jutil = require("jit.util") local vmdef = require("jit.vmdef") local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo -local type, format = type, string.format +local type, sub, format = type, string.sub, string.format local stdout, stderr = io.stdout, io.stderr -- Active flag and output file handle. @@ -89,7 +89,12 @@ end local function fmterr(err, info) if type(err) == "number" then if type(info) == "function" then info = fmtfunc(info) end - err = format(vmdef.traceerr[err], info) + local fmt = vmdef.traceerr[err] + if fmt == "NYI: bytecode %s" then + local oidx = 6 * info + info = sub(vmdef.bcnames, oidx+1, oidx+6) + end + err = format(fmt, info) end return err end diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h index 19ce30ad..08134dc5 100644 --- a/src/lj_traceerr.h +++ b/src/lj_traceerr.h @@ -13,7 +13,7 @@ TREDEF(STACKOV, "trace too deep") TREDEF(SNAPOV, "too many snapshots") TREDEF(BLACKL, "blacklisted") TREDEF(RETRY, "retry recording") -TREDEF(NYIBC, "NYI: bytecode %d") +TREDEF(NYIBC, "NYI: bytecode %s") /* Recording loop ops. */ TREDEF(LLEAVE, "leaving loop in root trace") From 7110b935672489afd6ba3eef3e5139d2f3bd05b6 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 00:31:06 +0200 Subject: [PATCH 10/15] OSX/iOS: Always generate 64 bit non-FAT Mach-O object files. Reported by Sergey Bronnikov. #1181 --- src/jit/bcsave.lua | 155 ++++++++++----------------------------------- 1 file changed, 34 insertions(+), 121 deletions(-) diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua index 131bf39b..0d79a70e 100644 --- a/src/jit/bcsave.lua +++ b/src/jit/bcsave.lua @@ -439,24 +439,12 @@ typedef struct { mach_header; uint32_t reserved; } mach_header_64; -typedef struct { - uint32_t cmd, cmdsize; - char segname[16]; - uint32_t vmaddr, vmsize, fileoff, filesize; - uint32_t maxprot, initprot, nsects, flags; -} mach_segment_command; typedef struct { uint32_t cmd, cmdsize; char segname[16]; uint64_t vmaddr, vmsize, fileoff, filesize; uint32_t maxprot, initprot, nsects, flags; } mach_segment_command_64; -typedef struct { - char sectname[16], segname[16]; - uint32_t addr, size; - uint32_t offset, align, reloff, nreloc, flags; - uint32_t reserved1, reserved2; -} mach_section; typedef struct { char sectname[16], segname[16]; uint64_t addr, size; @@ -466,133 +454,58 @@ typedef struct { typedef struct { uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; } mach_symtab_command; -typedef struct { - int32_t strx; - uint8_t type, sect; - int16_t desc; - uint32_t value; -} mach_nlist; typedef struct { int32_t strx; uint8_t type, sect; uint16_t desc; uint64_t value; } mach_nlist_64; -typedef struct -{ - int32_t magic, nfat_arch; -} mach_fat_header; -typedef struct -{ - int32_t cputype, cpusubtype, offset, size, align; -} mach_fat_arch; typedef struct { - struct { - mach_header hdr; - mach_segment_command seg; - mach_section sec; - mach_symtab_command sym; - } arch[1]; - mach_nlist sym_entry; - uint8_t space[4096]; -} mach_obj; -typedef struct { - struct { - mach_header_64 hdr; - mach_segment_command_64 seg; - mach_section_64 sec; - mach_symtab_command sym; - } arch[1]; + mach_header_64 hdr; + mach_segment_command_64 seg; + mach_section_64 sec; + mach_symtab_command sym; mach_nlist_64 sym_entry; uint8_t space[4096]; } mach_obj_64; -typedef struct { - mach_fat_header fat; - mach_fat_arch fat_arch[2]; - struct { - mach_header hdr; - mach_segment_command seg; - mach_section sec; - mach_symtab_command sym; - } arch[2]; - mach_nlist sym_entry; - uint8_t space[4096]; -} mach_fat_obj; -typedef struct { - mach_fat_header fat; - mach_fat_arch fat_arch[2]; - struct { - mach_header_64 hdr; - mach_segment_command_64 seg; - mach_section_64 sec; - mach_symtab_command sym; - } arch[2]; - mach_nlist_64 sym_entry; - uint8_t space[4096]; -} mach_fat_obj_64; ]] local symname = '_'..LJBC_PREFIX..ctx.modname - local isfat, is64, align, mobj = false, false, 4, "mach_obj" - if ctx.arch == "x64" then - is64, align, mobj = true, 8, "mach_obj_64" - elseif ctx.arch == "arm" then - isfat, mobj = true, "mach_fat_obj" - elseif ctx.arch == "arm64" then - is64, align, isfat, mobj = true, 8, true, "mach_fat_obj_64" - else - check(ctx.arch == "x86", "unsupported architecture for OSX") + local cputype, cpusubtype = 0x01000007, 3 + if ctx.arch ~= "x64" then + check(ctx.arch == "arm64", "unsupported architecture for OSX") + cputype, cpusubtype = 0x0100000c, 0 end local function aligned(v, a) return bit.band(v+a-1, -a) end - local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE. -- Create Mach-O object and fill in header. - local o = ffi.new(mobj) - local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) - local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12}, arm64={0x01000007,0x0100000c} })[ctx.arch] - local cpusubtype = ({ x86={3}, x64={3}, arm={3,9}, arm64={3,0} })[ctx.arch] - if isfat then - o.fat.magic = be32(0xcafebabe) - o.fat.nfat_arch = be32(#cpusubtype) - end + local o = ffi.new("mach_obj_64") + local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, 8) -- Fill in sections and symbols. - for i=0,#cpusubtype-1 do - local ofs = 0 - if isfat then - local a = o.fat_arch[i] - a.cputype = be32(cputype[i+1]) - a.cpusubtype = be32(cpusubtype[i+1]) - -- Subsequent slices overlap each other to share data. - ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) - a.offset = be32(ofs) - a.size = be32(mach_size-ofs+#s) - end - local a = o.arch[i] - a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface - a.hdr.cputype = cputype[i+1] - a.hdr.cpusubtype = cpusubtype[i+1] - a.hdr.filetype = 1 - a.hdr.ncmds = 2 - a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) - a.seg.cmd = is64 and 0x19 or 0x1 - a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) - a.seg.vmsize = #s - a.seg.fileoff = mach_size-ofs - a.seg.filesize = #s - a.seg.maxprot = 1 - a.seg.initprot = 1 - a.seg.nsects = 1 - ffi.copy(a.sec.sectname, "__data") - ffi.copy(a.sec.segname, "__DATA") - a.sec.size = #s - a.sec.offset = mach_size-ofs - a.sym.cmd = 2 - a.sym.cmdsize = ffi.sizeof(a.sym) - a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs - a.sym.nsyms = 1 - a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs - a.sym.strsize = aligned(#symname+2, align) - end + o.hdr.magic = 0xfeedfacf + o.hdr.cputype = cputype + o.hdr.cpusubtype = cpusubtype + o.hdr.filetype = 1 + o.hdr.ncmds = 2 + o.hdr.sizeofcmds = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)+ffi.sizeof(o.sym) + o.seg.cmd = 0x19 + o.seg.cmdsize = ffi.sizeof(o.seg)+ffi.sizeof(o.sec) + o.seg.vmsize = #s + o.seg.fileoff = mach_size + o.seg.filesize = #s + o.seg.maxprot = 1 + o.seg.initprot = 1 + o.seg.nsects = 1 + ffi.copy(o.sec.sectname, "__data") + ffi.copy(o.sec.segname, "__DATA") + o.sec.size = #s + o.sec.offset = mach_size + o.sym.cmd = 2 + o.sym.cmdsize = ffi.sizeof(o.sym) + o.sym.symoff = ffi.offsetof(o, "sym_entry") + o.sym.nsyms = 1 + o.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry) + o.sym.strsize = aligned(#symname+2, 8) o.sym_entry.type = 0xf o.sym_entry.sect = 1 o.sym_entry.strx = 1 From f5affaa6c4e7524e661484f22f24255f9a83eb47 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 01:33:19 +0200 Subject: [PATCH 11/15] FFI: Turn FFI finalizer table into a proper GC root. Reported by Sergey Bronnikov. #1168 --- src/lib_ffi.c | 20 ++------------------ src/lj_cdata.c | 2 +- src/lj_ctype.c | 12 ++++++++++++ src/lj_ctype.h | 2 +- src/lj_gc.c | 41 +++++++++++++++++------------------------ src/lj_obj.h | 3 +++ src/lj_state.c | 3 +++ 7 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/lib_ffi.c b/src/lib_ffi.c index ba783173..fb7f86f3 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -513,7 +513,7 @@ LJLIB_CF(ffi_new) LJLIB_REC(.) /* Handle ctype __gc metamethod. Use the fast lookup here. */ cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id); if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) { - GCtab *t = cts->finalizer; + GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]); if (gcref(t->metatable)) { /* Add to finalizer table, if still enabled. */ copyTV(L, lj_tab_set(L, t, o-1), tv); @@ -765,7 +765,7 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.) return 1; } -LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to miscmap table. */ +LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to miscmap table. */ LJLIB_CF(ffi_metatype) { @@ -791,8 +791,6 @@ LJLIB_CF(ffi_metatype) return 1; } -LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */ - LJLIB_CF(ffi_gc) LJLIB_REC(.) { GCcdata *cd = ffi_checkcdata(L, 1); @@ -825,19 +823,6 @@ LJLIB_PUSH(top-2) LJLIB_SET(arch) /* ------------------------------------------------------------------------ */ -/* Create special weak-keyed finalizer table. */ -static GCtab *ffi_finalizer(lua_State *L) -{ - /* NOBARRIER: The table is new (marked white). */ - GCtab *t = lj_tab_new(L, 0, 1); - settabV(L, L->top++, t); - setgcref(t->metatable, obj2gco(t)); - setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")), - lj_str_newlit(L, "k")); - t->nomm = (uint8_t)(~(1u<top++, (cts->miscmap = lj_tab_new(L, 0, 1))); - cts->finalizer = ffi_finalizer(L); LJ_LIB_REG(L, NULL, ffi_meta); /* NOBARRIER: basemt is a GC root. */ setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1))); diff --git a/src/lj_cdata.c b/src/lj_cdata.c index 77d9730f..2879e2a8 100644 --- a/src/lj_cdata.c +++ b/src/lj_cdata.c @@ -86,7 +86,7 @@ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd) void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it) { - GCtab *t = ctype_ctsG(G(L))->finalizer; + GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]); if (gcref(t->metatable)) { /* Add cdata to finalizer table, if still enabled. */ TValue *tv, tmp; diff --git a/src/lj_ctype.c b/src/lj_ctype.c index 8a4a55f8..0f6baac9 100644 --- a/src/lj_ctype.c +++ b/src/lj_ctype.c @@ -643,6 +643,18 @@ CTState *lj_ctype_init(lua_State *L) return cts; } +/* Create special weak-keyed finalizer table. */ +void lj_ctype_initfin(lua_State *L) +{ + /* NOBARRIER: The table is new (marked white). */ + GCtab *t = lj_tab_new(L, 0, 1); + setgcref(t->metatable, obj2gco(t)); + setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")), + lj_str_newlit(L, "k")); + t->nomm = (uint8_t)(~(1u<gcroot[GCROOT_FFI_FIN], obj2gco(t)); +} + /* Free C type table and state. */ void lj_ctype_freestate(global_State *g) { diff --git a/src/lj_ctype.h b/src/lj_ctype.h index cde1cf01..d53c4ea4 100644 --- a/src/lj_ctype.h +++ b/src/lj_ctype.h @@ -177,7 +177,6 @@ typedef struct CTState { MSize sizetab; /* Size of C type table. */ lua_State *L; /* Lua state (needed for errors and allocations). */ global_State *g; /* Global state. */ - GCtab *finalizer; /* Map of cdata to finalizer. */ GCtab *miscmap; /* Map of -CTypeID to metatable and cb slot to func. */ CCallback cb; /* Temporary callback state. */ CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */ @@ -476,6 +475,7 @@ LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); LJ_FUNC CTState *lj_ctype_init(lua_State *L); +LJ_FUNC void lj_ctype_initfin(lua_State *L); LJ_FUNC void lj_ctype_freestate(global_State *g); #endif diff --git a/src/lj_gc.c b/src/lj_gc.c index eebc751b..9cabdef0 100644 --- a/src/lj_gc.c +++ b/src/lj_gc.c @@ -108,9 +108,6 @@ static void gc_mark_start(global_State *g) gc_markobj(g, tabref(mainthread(g)->env)); gc_marktv(g, &g->registrytv); gc_mark_gcroot(g); -#if LJ_HASFFI - if (ctype_ctsG(g)) gc_markobj(g, ctype_ctsG(g)->finalizer); -#endif g->gc.state = GCSpropagate; } @@ -190,8 +187,7 @@ static int gc_traverse_tab(global_State *g, GCtab *t) } if (weak) { /* Weak tables are cleared in the atomic phase. */ #if LJ_HASFFI - CTState *cts = ctype_ctsG(g); - if (cts && cts->finalizer == t) { + if (gcref(g->gcroot[GCROOT_FFI_FIN]) == obj2gco(t)) { weak = (int)(~0u & ~LJ_GC_WEAKVAL); } else #endif @@ -556,7 +552,7 @@ static void gc_finalize(lua_State *L) o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; /* Resolve finalizer. */ setcdataV(L, &tmp, gco2cd(o)); - tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp); + tv = lj_tab_set(L, tabref(g->gcroot[GCROOT_FFI_FIN]), &tmp); if (!tvisnil(tv)) { g->gc.nocdatafin = 0; copyTV(L, &tmp, tv); @@ -588,23 +584,20 @@ void lj_gc_finalize_udata(lua_State *L) void lj_gc_finalize_cdata(lua_State *L) { global_State *g = G(L); - CTState *cts = ctype_ctsG(g); - if (cts) { - GCtab *t = cts->finalizer; - Node *node = noderef(t->node); - ptrdiff_t i; - setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */ - for (i = (ptrdiff_t)t->hmask; i >= 0; i--) - if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) { - GCobj *o = gcV(&node[i].key); - TValue tmp; - makewhite(g, o); - o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; - copyTV(L, &tmp, &node[i].val); - setnilV(&node[i].val); - gc_call_finalizer(g, L, &tmp, o); - } - } + GCtab *t = tabref(g->gcroot[GCROOT_FFI_FIN]); + Node *node = noderef(t->node); + ptrdiff_t i; + setgcrefnull(t->metatable); /* Mark finalizer table as disabled. */ + for (i = (ptrdiff_t)t->hmask; i >= 0; i--) + if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) { + GCobj *o = gcV(&node[i].key); + TValue tmp; + makewhite(g, o); + o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN; + copyTV(L, &tmp, &node[i].val); + setnilV(&node[i].val); + gc_call_finalizer(g, L, &tmp, o); + } } #endif @@ -720,7 +713,7 @@ static size_t gc_onestep(lua_State *L) return GCFINALIZECOST; } #if LJ_HASFFI - if (!g->gc.nocdatafin) lj_tab_rehash(L, ctype_ctsG(g)->finalizer); + if (!g->gc.nocdatafin) lj_tab_rehash(L, tabref(g->gcroot[GCROOT_FFI_FIN])); #endif g->gc.state = GCSpause; /* End of GC cycle. */ g->gc.debt = 0; diff --git a/src/lj_obj.h b/src/lj_obj.h index 2d4386e1..c0817663 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -579,6 +579,9 @@ typedef enum { GCROOT_BASEMT_NUM = GCROOT_BASEMT + ~LJ_TNUMX, GCROOT_IO_INPUT, /* Userdata for default I/O input file. */ GCROOT_IO_OUTPUT, /* Userdata for default I/O output file. */ +#if LJ_HASFFI + GCROOT_FFI_FIN, /* FFI finalizer table. */ +#endif GCROOT_MAX } GCRootID; diff --git a/src/lj_state.c b/src/lj_state.c index af17e4b5..6fd7d9ce 100644 --- a/src/lj_state.c +++ b/src/lj_state.c @@ -196,6 +196,9 @@ static TValue *cpluaopen(lua_State *L, lua_CFunction dummy, void *ud) lj_lex_init(L); fixstring(lj_err_str(L, LJ_ERR_ERRMEM)); /* Preallocate memory error msg. */ g->gc.threshold = 4*g->gc.total; +#if LJ_HASFFI + lj_ctype_initfin(L); +#endif lj_trace_initstate(g); lj_err_verify(); return NULL; From d032c637b1c1cf4a8cb4f52155459f6e91405bda Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 01:41:12 +0200 Subject: [PATCH 12/15] Fix compiler warning. --- src/lj_asm_arm64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lj_asm_arm64.h b/src/lj_asm_arm64.h index 5b40f4cc..0e5aee9a 100644 --- a/src/lj_asm_arm64.h +++ b/src/lj_asm_arm64.h @@ -787,7 +787,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) int destused = ra_used(ir); Reg dest = ra_dest(as, ir, allow); Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg tmp = RID_TMP, type = RID_NONE, key, tkey; + Reg tmp = RID_TMP, type = RID_NONE, key = RID_NONE, tkey; IRRef refkey = ir->op2; IRIns *irkey = IR(refkey); int isk = irref_isk(refkey); From 9b5e837ac2dfdc0638830c048a47ca9378c504d3 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 01:44:19 +0200 Subject: [PATCH 13/15] Fix segment release check in internal memory allocator. Thanks to Jinji Zeng. #1179 #1157 --- src/lj_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lj_alloc.c b/src/lj_alloc.c index 9adaa0e5..0c0c0c4f 100644 --- a/src/lj_alloc.c +++ b/src/lj_alloc.c @@ -975,7 +975,7 @@ static size_t release_unused_segments(mstate m) mchunkptr p = align_as_chunk(base); size_t psize = chunksize(p); /* Can unmap if first chunk holds entire segment and not pinned */ - if (!cinuse(p) && (char *)p + psize >= base + size - TOP_FOOT_SIZE) { + if (!cinuse(p) && (char *)p + psize == (char *)mem2chunk(sp)) { tchunkptr tp = (tchunkptr)p; if (p == m->dv) { m->dv = 0; From b3e498738962cdb08686f3dd612cf060382d88f2 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 19 Apr 2024 11:01:13 +0200 Subject: [PATCH 14/15] Windows/MSVC: Cleanup msvcbuild.bat and always generate PDB. Thanks to Miku AuahDark. #1127 --- src/msvcbuild.bat | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/msvcbuild.bat b/src/msvcbuild.bat index 91cfd065..13b8175a 100644 --- a/src/msvcbuild.bat +++ b/src/msvcbuild.bat @@ -13,10 +13,15 @@ @if not defined INCLUDE goto :FAIL @setlocal -@rem Add more debug flags here, e.g. DEBUGCFLAGS=/DLUA_USE_APICHECK +@rem Add more debug flags here, e.g. DEBUGCFLAGS=/DLUA_USE_ASSERT @set DEBUGCFLAGS= @set LJCOMPILE=cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline -@set LJDYNBUILD=/MD /DLUA_BUILD_AS_DLL +@set LJDYNBUILD=/DLUA_BUILD_AS_DLL /MD +@set LJDYNBUILD_DEBUG=/DLUA_BUILD_AS_DLL /MDd +@set LJCOMPILETARGET=/Zi +@set LJLINKTYPE=/DEBUG /RELEASE +@set LJLINKTYPE_DEBUG=/DEBUG +@set LJLINKTARGET=/OPT:REF /OPT:ICF /INCREMENTAL:NO @set LJLINK=link /nologo @set LJMT=mt /nologo @set LJLIB=lib /nologo /nodefaultlib @@ -25,7 +30,6 @@ @set DASC=vm_x64.dasc @set LJDLLNAME=lua51.dll @set LJLIBNAME=lua51.lib -@set BUILDTYPE=release @set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c @setlocal @@ -92,12 +96,12 @@ buildvm -m folddef -o lj_folddef.h lj_opt_fold.c @if "%1" neq "debug" goto :NODEBUG @shift -@set BUILDTYPE=debug -@set LJCOMPILE=%LJCOMPILE% /Zi %DEBUGCFLAGS% -@set LJDYNBUILD=/MDd /DLUA_BUILD_AS_DLL -@set LJLINK=%LJLINK% /opt:ref /opt:icf /incremental:no +@set LJCOMPILE=%LJCOMPILE% %DEBUGCFLAGS% +@set LJDYNBUILD=%LJDYNBUILD_DEBUG% +@set LJLINKTYPE=%LJLINKTYPE_DEBUG% :NODEBUG -@set LJLINK=%LJLINK% /%BUILDTYPE% +@set LJCOMPILE=%LJCOMPILE% %LJCOMPILETARGET% +@set LJLINK=%LJLINK% %LJLINKTYPE% %LJLINKTARGET% @if "%1"=="amalg" goto :AMALGDLL @if "%1"=="static" goto :STATIC %LJCOMPILE% %LJDYNBUILD% lj_*.c lib_*.c From 5790d253972c9d78a0c2aece527eda5b134bbbf7 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Mon, 22 Apr 2024 10:06:42 +0200 Subject: [PATCH 15/15] OSX/iOS: Fix SDK incompatibility. Thanks to Ryan Carsten Schmidt. #1189 --- src/lj_arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lj_arch.h b/src/lj_arch.h index 026e741f..e6264398 100644 --- a/src/lj_arch.h +++ b/src/lj_arch.h @@ -124,7 +124,7 @@ #define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS) #define LJ_TARGET_DLOPEN LJ_TARGET_POSIX -#if TARGET_OS_IPHONE +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE #define LJ_TARGET_IOS 1 #else #define LJ_TARGET_IOS 0