Skip to content

Commit

Permalink
Add support for full-range 64 bit lightuserdata.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Pall committed Sep 29, 2020
1 parent e67e204 commit e9af1ab
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 67 deletions.
11 changes: 0 additions & 11 deletions doc/status.html
Expand Up @@ -91,17 +91,6 @@ <h2>Current Status</h2>
<tt>lua_atpanic</tt> on x64. This issue will be fixed with the new
garbage collector.
</li>
<li>
LuaJIT on 64 bit systems provides a <b>limited range</b> of 47 bits for the
<b>legacy <tt>lightuserdata</tt></b> 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 <tt>lightuserdata</tt> 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.
</li>
</ul>
<br class="flush">
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/jit/dump.lua
Expand Up @@ -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"
Expand Down
12 changes: 6 additions & 6 deletions src/lib_debug.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand Down
14 changes: 7 additions & 7 deletions src/lib_jit.c
Expand Up @@ -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;
Expand All @@ -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) : "",
Expand All @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions src/lib_package.c
Expand Up @@ -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)
{
Expand All @@ -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 */
}
Expand All @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion src/lib_string.c
Expand Up @@ -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");
Expand Down
40 changes: 36 additions & 4 deletions src/lj_api.c
Expand Up @@ -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;
}
Expand All @@ -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) ------------------------------------- */
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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. */
Expand Down
2 changes: 1 addition & 1 deletion src/lj_ccall.c
Expand Up @@ -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. */
Expand Down
2 changes: 1 addition & 1 deletion src/lj_cconv.c
Expand Up @@ -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) {
Expand Down
6 changes: 2 additions & 4 deletions src/lj_crecord.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion src/lj_dispatch.c
Expand Up @@ -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 {
Expand Down
6 changes: 4 additions & 2 deletions src/lj_ir.c
Expand Up @@ -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: {
Expand Down
5 changes: 3 additions & 2 deletions src/lj_obj.c
Expand Up @@ -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))
Expand Down

0 comments on commit e9af1ab

Please sign in to comment.