From e9af1abec542e6f9851ff2368e7f196b6382a44c Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Wed, 30 Sep 2020 01:31:27 +0200 Subject: [PATCH] Add support for full-range 64 bit lightuserdata. --- doc/status.html | 11 --------- src/jit/dump.lua | 4 +++- src/lib_debug.c | 12 +++++----- src/lib_jit.c | 14 ++++++------ src/lib_package.c | 8 +++---- src/lib_string.c | 2 +- src/lj_api.c | 40 +++++++++++++++++++++++++++++---- src/lj_ccall.c | 2 +- src/lj_cconv.c | 2 +- src/lj_crecord.c | 6 ++--- src/lj_dispatch.c | 2 +- src/lj_ir.c | 6 +++-- src/lj_obj.c | 5 +++-- src/lj_obj.h | 57 ++++++++++++++++++++++++++++++----------------- src/lj_snap.c | 9 +++++++- src/lj_state.c | 6 +++++ src/lj_strfmt.c | 2 +- 17 files changed, 121 insertions(+), 67 deletions(-) diff --git a/doc/status.html b/doc/status.html index 0aafe13a22..fd0ae8bae1 100644 --- a/doc/status.html +++ b/doc/status.html @@ -91,17 +91,6 @@

Current Status

lua_atpanic on x64. This issue will be fixed with the new garbage collector. -
  • -LuaJIT on 64 bit systems provides a limited range of 47 bits for the -legacy lightuserdata data type. -This is only relevant on x64 systems which use the negative part of the -virtual address space in user mode, e.g. Solaris/x64, and on ARM64 systems -configured with a 48 bit or 52 bit VA. -Avoid using lightuserdata to hold pointers that may point outside -of that range, e.g. variables on the stack. In general, avoid this data -type for new code and replace it with (much more performant) FFI bindings. -FFI cdata pointers can address the full 64 bit range. -

  • diff --git a/src/jit/dump.lua b/src/jit/dump.lua index 0cb38b5857..06d1e258c2 100644 --- a/src/jit/dump.lua +++ b/src/jit/dump.lua @@ -315,7 +315,9 @@ local function formatk(tr, idx, sn) local tn = type(k) local s if tn == "number" then - if band(sn or 0, 0x30000) ~= 0 then + if t < 12 then + s = k == 0 and "NULL" or format("[0x%08x]", k) + elseif band(sn or 0, 0x30000) ~= 0 then s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz" elseif k == 2^52+2^51 then s = "bias" diff --git a/src/lib_debug.c b/src/lib_debug.c index 6737c462f6..41b30e170b 100644 --- a/src/lib_debug.c +++ b/src/lib_debug.c @@ -231,8 +231,8 @@ LJLIB_CF(debug_upvalueid) int32_t n = lj_lib_checkint(L, 2) - 1; if ((uint32_t)n >= fn->l.nupvalues) lj_err_arg(L, 2, LJ_ERR_IDXRNG); - setlightudV(L->top-1, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) : - (void *)&fn->c.upvalue[n]); + lua_pushlightuserdata(L, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) : + (void *)&fn->c.upvalue[n]); return 1; } @@ -283,13 +283,13 @@ LJLIB_CF(debug_setuservalue) /* ------------------------------------------------------------------------ */ -#define KEY_HOOK ((void *)0x3004) +#define KEY_HOOK (U64x(80000000,00000000)|'h') static void hookf(lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail return"}; - lua_pushlightuserdata(L, KEY_HOOK); + (L->top++)->u64 = KEY_HOOK; lua_rawget(L, LUA_REGISTRYINDEX); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); @@ -334,7 +334,7 @@ LJLIB_CF(debug_sethook) count = luaL_optint(L, arg+3, 0); func = hookf; mask = makemask(smask, count); } - lua_pushlightuserdata(L, KEY_HOOK); + (L->top++)->u64 = KEY_HOOK; lua_pushvalue(L, arg+1); lua_rawset(L, LUA_REGISTRYINDEX); lua_sethook(L, func, mask, count); @@ -349,7 +349,7 @@ LJLIB_CF(debug_gethook) if (hook != NULL && hook != hookf) { /* external hook? */ lua_pushliteral(L, "external hook"); } else { - lua_pushlightuserdata(L, KEY_HOOK); + (L->top++)->u64 = KEY_HOOK; lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ } lua_pushstring(L, unmakemask(mask, buff)); diff --git a/src/lib_jit.c b/src/lib_jit.c index 21e01d3ed2..dd2628f6fc 100644 --- a/src/lib_jit.c +++ b/src/lib_jit.c @@ -547,15 +547,15 @@ LJLIB_CF(jit_opt_start) /* Not loaded by default, use: local profile = require("jit.profile") */ -static const char KEY_PROFILE_THREAD = 't'; -static const char KEY_PROFILE_FUNC = 'f'; +#define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t') +#define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f') static void jit_profile_callback(lua_State *L2, lua_State *L, int samples, int vmstate) { TValue key; cTValue *tv; - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); + key.u64 = KEY_PROFILE_FUNC; tv = lj_tab_get(L, tabV(registry(L)), &key); if (tvisfunc(tv)) { char vmst = (char)vmstate; @@ -582,9 +582,9 @@ LJLIB_CF(jit_profile_start) lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */ TValue key; /* Anchor thread and function in registry. */ - setlightudV(&key, (void *)&KEY_PROFILE_THREAD); + key.u64 = KEY_PROFILE_THREAD; setthreadV(L, lj_tab_set(L, registry, &key), L2); - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); + key.u64 = KEY_PROFILE_FUNC; setfuncV(L, lj_tab_set(L, registry, &key), func); lj_gc_anybarriert(L, registry); luaJIT_profile_start(L, mode ? strdata(mode) : "", @@ -599,9 +599,9 @@ LJLIB_CF(jit_profile_stop) TValue key; luaJIT_profile_stop(L); registry = tabV(registry(L)); - setlightudV(&key, (void *)&KEY_PROFILE_THREAD); + key.u64 = KEY_PROFILE_THREAD; setnilV(lj_tab_set(L, registry, &key)); - setlightudV(&key, (void *)&KEY_PROFILE_FUNC); + key.u64 = KEY_PROFILE_FUNC; setnilV(lj_tab_set(L, registry, &key)); lj_gc_anybarriert(L, registry); return 0; diff --git a/src/lib_package.c b/src/lib_package.c index b6917121ea..752b23b4d9 100644 --- a/src/lib_package.c +++ b/src/lib_package.c @@ -425,7 +425,7 @@ static int lj_cf_package_loader_preload(lua_State *L) /* ------------------------------------------------------------------------ */ -#define sentinel ((void *)0x4004) +#define KEY_SENTINEL (U64x(80000000,00000000)|'s') static int lj_cf_package_require(lua_State *L) { @@ -435,7 +435,7 @@ static int lj_cf_package_require(lua_State *L) lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); if (lua_toboolean(L, -1)) { /* is it there? */ - if (lua_touserdata(L, -1) == sentinel) /* check loops */ + if ((L->top-1)->u64 == KEY_SENTINEL) /* check loops */ luaL_error(L, "loop or previous error loading module " LUA_QS, name); return 1; /* package is already loaded */ } @@ -458,14 +458,14 @@ static int lj_cf_package_require(lua_State *L) else lua_pop(L, 1); } - lua_pushlightuserdata(L, sentinel); + (L->top++)->u64 = KEY_SENTINEL; lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ lua_pushstring(L, name); /* pass name as argument to module */ lua_call(L, 1, 1); /* run loaded module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_getfield(L, 2, name); - if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + if ((L->top-1)->u64 == KEY_SENTINEL) { /* module did not set a value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ diff --git a/src/lib_string.c b/src/lib_string.c index 0d9290bcdd..969e04233a 100644 --- a/src/lib_string.c +++ b/src/lib_string.c @@ -714,7 +714,7 @@ LJLIB_CF(string_format) LJLIB_REC(.) lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg)); break; case STRFMT_PTR: /* No formatting. */ - lj_strfmt_putptr(sb, lj_obj_ptr(L->base+arg-1)); + lj_strfmt_putptr(sb, lj_obj_ptr(G(L), L->base+arg-1)); break; default: lj_assertL(0, "bad string format type"); diff --git a/src/lj_api.c b/src/lj_api.c index f53ecc35ac..ecaf8a2b18 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -608,7 +608,7 @@ LUA_API void *lua_touserdata(lua_State *L, int idx) if (tvisudata(o)) return uddata(udataV(o)); else if (tvislightud(o)) - return lightudV(o); + return lightudV(G(L), o); else return NULL; } @@ -621,7 +621,7 @@ LUA_API lua_State *lua_tothread(lua_State *L, int idx) LUA_API const void *lua_topointer(lua_State *L, int idx) { - return lj_obj_ptr(index2adr(L, idx)); + return lj_obj_ptr(G(L), index2adr(L, idx)); } /* -- Stack setters (object creation) ------------------------------------- */ @@ -707,9 +707,38 @@ LUA_API void lua_pushboolean(lua_State *L, int b) incr_top(L); } +#if LJ_64 +static void *lightud_intern(lua_State *L, void *p) +{ + global_State *g = G(L); + uint64_t u = (uint64_t)p; + uint32_t up = lightudup(u); + uint32_t *segmap = mref(g->gc.lightudseg, uint32_t); + MSize segnum = g->gc.lightudnum; + if (segmap) { + MSize seg; + for (seg = 0; seg <= segnum; seg++) + if (segmap[seg] == up) /* Fast path. */ + return (void *)(((uint64_t)seg << LJ_LIGHTUD_BITS_LO) | lightudlo(u)); + segnum++; + } + if (!((segnum-1) & segnum) && segnum != 1) { + if (segnum >= (1 << LJ_LIGHTUD_BITS_SEG)) lj_err_msg(L, LJ_ERR_BADLU); + lj_mem_reallocvec(L, segmap, segnum, segnum ? 2*segnum : 2u, uint32_t); + setmref(g->gc.lightudseg, segmap); + } + g->gc.lightudnum = segnum; + segmap[segnum] = up; + return (void *)(((uint64_t)segnum << LJ_LIGHTUD_BITS_LO) | lightudlo(u)); +} +#endif + LUA_API void lua_pushlightuserdata(lua_State *L, void *p) { - setlightudV(L->top, checklightudptr(L, p)); +#if LJ_64 + p = lightud_intern(L, p); +#endif + setrawlightudV(L->top, p); incr_top(L); } @@ -1149,7 +1178,10 @@ static TValue *cpcall(lua_State *L, lua_CFunction func, void *ud) fn->c.f = func; setfuncV(L, top++, fn); if (LJ_FR2) setnilV(top++); - setlightudV(top++, checklightudptr(L, ud)); +#if LJ_64 + ud = lightud_intern(L, ud); +#endif + setrawlightudV(top++, ud); cframe_nres(L->cframe) = 1+0; /* Zero results. */ L->top = top; return top-1; /* Now call the newly allocated C function. */ diff --git a/src/lj_ccall.c b/src/lj_ccall.c index 5ac1b4dad4..c126ddcc58 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c @@ -1167,7 +1167,7 @@ int lj_ccall_func(lua_State *L, GCcdata *cd) lj_vm_ffi_call(&cc); if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ TValue tv; - setlightudV(&tv, (void *)cc.func); + tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000); setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); } ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */ diff --git a/src/lj_cconv.c b/src/lj_cconv.c index 400c2ae66f..37c8aa1af7 100644 --- a/src/lj_cconv.c +++ b/src/lj_cconv.c @@ -620,7 +620,7 @@ void lj_cconv_ct_tv(CTState *cts, CType *d, if (ud->udtype == UDTYPE_IO_FILE) tmpptr = *(void **)tmpptr; } else if (tvislightud(o)) { - tmpptr = lightudV(o); + tmpptr = lightudV(cts->g, o); } else if (tvisfunc(o)) { void *p = lj_ccallback_new(cts, d, funcV(o)); if (p) { diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 7ae1479ef0..f6824bff61 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c @@ -646,8 +646,7 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) } } else if (tref_islightud(sp)) { #if LJ_64 - sp = emitir(IRT(IR_BAND, IRT_P64), sp, - lj_ir_kint64(J, U64x(00007fff,ffffffff))); + lj_trace_err(J, LJ_TRERR_NYICONV); #endif } else { /* NYI: tref_istab(sp). */ IRType t; @@ -1212,8 +1211,7 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) TRef tr; TValue tv; /* Check for blacklisted C functions that might call a callback. */ - setlightudV(&tv, - cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4)); + tv.u64 = ((uintptr_t)cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4) >> 2) | U64x(800000000, 00000000); if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv))) lj_trace_err(J, LJ_TRERR_BLACKL); if (ctype_isvoid(ctr->info)) { diff --git a/src/lj_dispatch.c b/src/lj_dispatch.c index c608e2237e..1d0ff549ef 100644 --- a/src/lj_dispatch.c +++ b/src/lj_dispatch.c @@ -295,7 +295,7 @@ int luaJIT_setmode(lua_State *L, int idx, int mode) if (idx != 0) { cTValue *tv = idx > 0 ? L->base + (idx-1) : L->top + idx; if (tvislightud(tv)) - g->wrapf = (lua_CFunction)lightudV(tv); + g->wrapf = (lua_CFunction)lightudV(g, tv); else return 0; /* Failed. */ } else { diff --git a/src/lj_ir.c b/src/lj_ir.c index b5e94eb84e..3ce2995479 100644 --- a/src/lj_ir.c +++ b/src/lj_ir.c @@ -389,8 +389,10 @@ void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir) case IR_KPRI: setpriV(tv, irt_toitype(ir->t)); break; case IR_KINT: setintV(tv, ir->i); break; case IR_KGC: setgcV(L, tv, ir_kgc(ir), irt_toitype(ir->t)); break; - case IR_KPTR: case IR_KKPTR: setlightudV(tv, ir_kptr(ir)); break; - case IR_KNULL: setlightudV(tv, NULL); break; + case IR_KPTR: case IR_KKPTR: + setnumV(tv, (lua_Number)(uintptr_t)ir_kptr(ir)); + break; + case IR_KNULL: setintV(tv, 0); break; case IR_KNUM: setnumV(tv, ir_knum(ir)->n); break; #if LJ_HASFFI case IR_KINT64: { diff --git a/src/lj_obj.c b/src/lj_obj.c index 5d16e0e547..6458c6ad01 100644 --- a/src/lj_obj.c +++ b/src/lj_obj.c @@ -34,12 +34,13 @@ int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2) } /* Return pointer to object or its object data. */ -const void * LJ_FASTCALL lj_obj_ptr(cTValue *o) +const void * LJ_FASTCALL lj_obj_ptr(global_State *g, cTValue *o) { + UNUSED(g); if (tvisudata(o)) return uddata(udataV(o)); else if (tvislightud(o)) - return lightudV(o); + return lightudV(g, o); else if (LJ_HASFFI && tviscdata(o)) return cdataptr(cdataV(o)); else if (tvisgcv(o)) diff --git a/src/lj_obj.h b/src/lj_obj.h index 9d4bec0832..9a783a5c21 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -232,7 +232,7 @@ typedef const TValue cTValue; ** ---MSW---.---LSW--- ** primitive types | itype | | ** lightuserdata | itype | void * | (32 bit platforms) -** lightuserdata |ffff| void * | (64 bit platforms, 47 bit pointers) +** lightuserdata |ffff|seg| ofs | (64 bit platforms) ** GC objects | itype | GCRef | ** int (LJ_DUALNUM)| itype | int | ** number -------double------ @@ -245,7 +245,8 @@ typedef const TValue cTValue; ** ** ------MSW------.------LSW------ ** primitive types |1..1|itype|1..................1| -** GC objects/lightud |1..1|itype|-------GCRef--------| +** GC objects |1..1|itype|-------GCRef--------| +** lightuserdata |1..1|itype|seg|------ofs-------| ** int (LJ_DUALNUM) |1..1|itype|0..0|-----int-------| ** number ------------double------------- ** @@ -285,6 +286,12 @@ typedef const TValue cTValue; #define LJ_GCVMASK (((uint64_t)1 << 47) - 1) #endif +#if LJ_64 +/* To stay within 47 bits, lightuserdata is segmented. */ +#define LJ_LIGHTUD_BITS_SEG 8 +#define LJ_LIGHTUD_BITS_LO (47 - LJ_LIGHTUD_BITS_SEG) +#endif + /* -- String object ------------------------------------------------------- */ typedef uint32_t StrHash; /* String hash value. */ @@ -580,7 +587,11 @@ typedef struct GCState { uint8_t currentwhite; /* Current white color. */ uint8_t state; /* GC state. */ uint8_t nocdatafin; /* No cdata finalizer called. */ - uint8_t unused2; +#if LJ_64 + uint8_t lightudnum; /* Number of lightuserdata segments - 1. */ +#else + uint8_t unused1; +#endif MSize sweepstr; /* Sweep position in string table. */ GCRef root; /* List of all collectable objects. */ MRef sweep; /* Sweep position in root list. */ @@ -592,6 +603,9 @@ typedef struct GCState { GCSize estimate; /* Estimate of memory actually in use. */ MSize stepmul; /* Incremental GC step granularity. */ MSize pause; /* Pause between successive GC cycles. */ +#if LJ_64 + MRef lightudseg; /* Upper bits of lightuserdata segments. */ +#endif } GCState; /* String interning state. */ @@ -813,10 +827,23 @@ typedef union GCobj { #endif #define boolV(o) check_exp(tvisbool(o), (LJ_TFALSE - itype(o))) #if LJ_64 -#define lightudV(o) \ - check_exp(tvislightud(o), (void *)((o)->u64 & U64x(00007fff,ffffffff))) +#define lightudseg(u) \ + (((u) >> LJ_LIGHTUD_BITS_LO) & ((1 << LJ_LIGHTUD_BITS_SEG)-1)) +#define lightudlo(u) \ + ((u) & (((uint64_t)1 << LJ_LIGHTUD_BITS_LO) - 1)) +#define lightudup(p) \ + ((uint32_t)(((p) >> LJ_LIGHTUD_BITS_LO) << (LJ_LIGHTUD_BITS_LO-32))) +static LJ_AINLINE void *lightudV(global_State *g, cTValue *o) +{ + uint64_t u = o->u64; + uint64_t seg = lightudseg(u); + uint32_t *segmap = mref(g->gc.lightudseg, uint32_t); + lj_assertG(tvislightud(o), "lightuserdata expected"); + lj_assertG(seg <= g->gc.lightudnum, "bad lightuserdata segment %d", seg); + return (void *)(((uint64_t)segmap[seg] << 32) | lightudlo(u)); +} #else -#define lightudV(o) check_exp(tvislightud(o), gcrefp((o)->gcr, void)) +#define lightudV(g, o) check_exp(tvislightud(o), gcrefp((o)->gcr, void)) #endif #define gcV(o) check_exp(tvisgcv(o), gcval(o)) #define strV(o) check_exp(tvisstr(o), &gcval(o)->str) @@ -842,7 +869,7 @@ typedef union GCobj { #define setpriV(o, i) (setitype((o), (i))) #endif -static LJ_AINLINE void setlightudV(TValue *o, void *p) +static LJ_AINLINE void setrawlightudV(TValue *o, void *p) { #if LJ_GC64 o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD) << 47); @@ -853,24 +880,14 @@ static LJ_AINLINE void setlightudV(TValue *o, void *p) #endif } -#if LJ_64 -#define checklightudptr(L, p) \ - (((uint64_t)(p) >> 47) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) -#else -#define checklightudptr(L, p) (p) -#endif - -#if LJ_FR2 +#if LJ_FR2 || LJ_32 #define contptr(f) ((void *)(f)) #define setcont(o, f) ((o)->u64 = (uint64_t)(uintptr_t)contptr(f)) -#elif LJ_64 +#else #define contptr(f) \ ((void *)(uintptr_t)(uint32_t)((intptr_t)(f) - (intptr_t)lj_vm_asm_begin)) #define setcont(o, f) \ ((o)->u64 = (uint64_t)(void *)(f) - (uint64_t)lj_vm_asm_begin) -#else -#define contptr(f) ((void *)(f)) -#define setcont(o, f) setlightudV((o), contptr(f)) #endif static LJ_AINLINE void checklivetv(lua_State *L, TValue *o, const char *msg) @@ -1016,6 +1033,6 @@ LJ_DATA const char *const lj_obj_itypename[~LJ_TNUMX+1]; /* Compare two objects without calling metamethods. */ LJ_FUNC int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2); -LJ_FUNC const void * LJ_FASTCALL lj_obj_ptr(cTValue *o); +LJ_FUNC const void * LJ_FASTCALL lj_obj_ptr(global_State *g, cTValue *o); #endif diff --git a/src/lj_snap.c b/src/lj_snap.c index 36f815285c..f1358cf29b 100644 --- a/src/lj_snap.c +++ b/src/lj_snap.c @@ -638,7 +638,14 @@ static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex, IRType1 t = ir->t; RegSP rs = ir->prev; if (irref_isk(ref)) { /* Restore constant slot. */ - lj_ir_kvalue(J->L, o, ir); + if (ir->o == IR_KPTR) { + o->u64 = (uint64_t)(uintptr_t)ir_kptr(ir); + } else { + lj_assertJ(!(ir->o == IR_KKPTR || ir->o == IR_KNULL), + "restore of const from IR %04d with bad op %d", + ref - REF_BIAS, ir->o); + lj_ir_kvalue(J->L, o, ir); + } return; } if (LJ_UNLIKELY(bloomtest(rfilt, ref))) diff --git a/src/lj_state.c b/src/lj_state.c index 4f77e71f19..2b031d97d5 100644 --- a/src/lj_state.c +++ b/src/lj_state.c @@ -174,6 +174,12 @@ static void close_state(lua_State *L) lj_str_freetab(g); lj_buf_free(g, &g->tmpbuf); lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue); +#if LJ_64 + if (mref(g->gc.lightudseg, uint32_t)) { + MSize segnum = g->gc.lightudnum ? (2 << lj_fls(g->gc.lightudnum)) : 2; + lj_mem_freevec(g, mref(g->gc.lightudseg, uint32_t), segnum, uint32_t); + } +#endif lj_assertG(g->gc.total == sizeof(GG_State), "memory leak of %lld bytes", (long long)(g->gc.total - sizeof(GG_State))); diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c index 331d9474c0..207c544e5a 100644 --- a/src/lj_strfmt.c +++ b/src/lj_strfmt.c @@ -393,7 +393,7 @@ GCstr * LJ_FASTCALL lj_strfmt_obj(lua_State *L, cTValue *o) p = lj_buf_wmem(p, "builtin#", 8); p = lj_strfmt_wint(p, funcV(o)->c.ffid); } else { - p = lj_strfmt_wptr(p, lj_obj_ptr(o)); + p = lj_strfmt_wptr(p, lj_obj_ptr(G(L), o)); } return lj_str_new(L, buf, (size_t)(p - buf)); }