Skip to content

Commit e9af1ab

Browse files
author
Mike Pall
committed
Add support for full-range 64 bit lightuserdata.
1 parent e67e204 commit e9af1ab

17 files changed

+121
-67
lines changed

doc/status.html

-11
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,6 @@ <h2>Current Status</h2>
9191
<tt>lua_atpanic</tt> on x64. This issue will be fixed with the new
9292
garbage collector.
9393
</li>
94-
<li>
95-
LuaJIT on 64 bit systems provides a <b>limited range</b> of 47 bits for the
96-
<b>legacy <tt>lightuserdata</tt></b> data type.
97-
This is only relevant on x64 systems which use the negative part of the
98-
virtual address space in user mode, e.g. Solaris/x64, and on ARM64 systems
99-
configured with a 48 bit or 52 bit VA.
100-
Avoid using <tt>lightuserdata</tt> to hold pointers that may point outside
101-
of that range, e.g. variables on the stack. In general, avoid this data
102-
type for new code and replace it with (much more performant) FFI bindings.
103-
FFI cdata pointers can address the full 64 bit range.
104-
</li>
10594
</ul>
10695
<br class="flush">
10796
</div>

src/jit/dump.lua

+3-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,9 @@ local function formatk(tr, idx, sn)
315315
local tn = type(k)
316316
local s
317317
if tn == "number" then
318-
if band(sn or 0, 0x30000) ~= 0 then
318+
if t < 12 then
319+
s = k == 0 and "NULL" or format("[0x%08x]", k)
320+
elseif band(sn or 0, 0x30000) ~= 0 then
319321
s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz"
320322
elseif k == 2^52+2^51 then
321323
s = "bias"

src/lib_debug.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ LJLIB_CF(debug_upvalueid)
231231
int32_t n = lj_lib_checkint(L, 2) - 1;
232232
if ((uint32_t)n >= fn->l.nupvalues)
233233
lj_err_arg(L, 2, LJ_ERR_IDXRNG);
234-
setlightudV(L->top-1, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
235-
(void *)&fn->c.upvalue[n]);
234+
lua_pushlightuserdata(L, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
235+
(void *)&fn->c.upvalue[n]);
236236
return 1;
237237
}
238238

@@ -283,13 +283,13 @@ LJLIB_CF(debug_setuservalue)
283283

284284
/* ------------------------------------------------------------------------ */
285285

286-
#define KEY_HOOK ((void *)0x3004)
286+
#define KEY_HOOK (U64x(80000000,00000000)|'h')
287287

288288
static void hookf(lua_State *L, lua_Debug *ar)
289289
{
290290
static const char *const hooknames[] =
291291
{"call", "return", "line", "count", "tail return"};
292-
lua_pushlightuserdata(L, KEY_HOOK);
292+
(L->top++)->u64 = KEY_HOOK;
293293
lua_rawget(L, LUA_REGISTRYINDEX);
294294
if (lua_isfunction(L, -1)) {
295295
lua_pushstring(L, hooknames[(int)ar->event]);
@@ -334,7 +334,7 @@ LJLIB_CF(debug_sethook)
334334
count = luaL_optint(L, arg+3, 0);
335335
func = hookf; mask = makemask(smask, count);
336336
}
337-
lua_pushlightuserdata(L, KEY_HOOK);
337+
(L->top++)->u64 = KEY_HOOK;
338338
lua_pushvalue(L, arg+1);
339339
lua_rawset(L, LUA_REGISTRYINDEX);
340340
lua_sethook(L, func, mask, count);
@@ -349,7 +349,7 @@ LJLIB_CF(debug_gethook)
349349
if (hook != NULL && hook != hookf) { /* external hook? */
350350
lua_pushliteral(L, "external hook");
351351
} else {
352-
lua_pushlightuserdata(L, KEY_HOOK);
352+
(L->top++)->u64 = KEY_HOOK;
353353
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
354354
}
355355
lua_pushstring(L, unmakemask(mask, buff));

src/lib_jit.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -547,15 +547,15 @@ LJLIB_CF(jit_opt_start)
547547

548548
/* Not loaded by default, use: local profile = require("jit.profile") */
549549

550-
static const char KEY_PROFILE_THREAD = 't';
551-
static const char KEY_PROFILE_FUNC = 'f';
550+
#define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t')
551+
#define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f')
552552

553553
static void jit_profile_callback(lua_State *L2, lua_State *L, int samples,
554554
int vmstate)
555555
{
556556
TValue key;
557557
cTValue *tv;
558-
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
558+
key.u64 = KEY_PROFILE_FUNC;
559559
tv = lj_tab_get(L, tabV(registry(L)), &key);
560560
if (tvisfunc(tv)) {
561561
char vmst = (char)vmstate;
@@ -582,9 +582,9 @@ LJLIB_CF(jit_profile_start)
582582
lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */
583583
TValue key;
584584
/* Anchor thread and function in registry. */
585-
setlightudV(&key, (void *)&KEY_PROFILE_THREAD);
585+
key.u64 = KEY_PROFILE_THREAD;
586586
setthreadV(L, lj_tab_set(L, registry, &key), L2);
587-
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
587+
key.u64 = KEY_PROFILE_FUNC;
588588
setfuncV(L, lj_tab_set(L, registry, &key), func);
589589
lj_gc_anybarriert(L, registry);
590590
luaJIT_profile_start(L, mode ? strdata(mode) : "",
@@ -599,9 +599,9 @@ LJLIB_CF(jit_profile_stop)
599599
TValue key;
600600
luaJIT_profile_stop(L);
601601
registry = tabV(registry(L));
602-
setlightudV(&key, (void *)&KEY_PROFILE_THREAD);
602+
key.u64 = KEY_PROFILE_THREAD;
603603
setnilV(lj_tab_set(L, registry, &key));
604-
setlightudV(&key, (void *)&KEY_PROFILE_FUNC);
604+
key.u64 = KEY_PROFILE_FUNC;
605605
setnilV(lj_tab_set(L, registry, &key));
606606
lj_gc_anybarriert(L, registry);
607607
return 0;

src/lib_package.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ static int lj_cf_package_loader_preload(lua_State *L)
425425

426426
/* ------------------------------------------------------------------------ */
427427

428-
#define sentinel ((void *)0x4004)
428+
#define KEY_SENTINEL (U64x(80000000,00000000)|'s')
429429

430430
static int lj_cf_package_require(lua_State *L)
431431
{
@@ -435,7 +435,7 @@ static int lj_cf_package_require(lua_State *L)
435435
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
436436
lua_getfield(L, 2, name);
437437
if (lua_toboolean(L, -1)) { /* is it there? */
438-
if (lua_touserdata(L, -1) == sentinel) /* check loops */
438+
if ((L->top-1)->u64 == KEY_SENTINEL) /* check loops */
439439
luaL_error(L, "loop or previous error loading module " LUA_QS, name);
440440
return 1; /* package is already loaded */
441441
}
@@ -458,14 +458,14 @@ static int lj_cf_package_require(lua_State *L)
458458
else
459459
lua_pop(L, 1);
460460
}
461-
lua_pushlightuserdata(L, sentinel);
461+
(L->top++)->u64 = KEY_SENTINEL;
462462
lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
463463
lua_pushstring(L, name); /* pass name as argument to module */
464464
lua_call(L, 1, 1); /* run loaded module */
465465
if (!lua_isnil(L, -1)) /* non-nil return? */
466466
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
467467
lua_getfield(L, 2, name);
468-
if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */
468+
if ((L->top-1)->u64 == KEY_SENTINEL) { /* module did not set a value? */
469469
lua_pushboolean(L, 1); /* use true as result */
470470
lua_pushvalue(L, -1); /* extra copy to be returned */
471471
lua_setfield(L, 2, name); /* _LOADED[name] = true */

src/lib_string.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ LJLIB_CF(string_format) LJLIB_REC(.)
714714
lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg));
715715
break;
716716
case STRFMT_PTR: /* No formatting. */
717-
lj_strfmt_putptr(sb, lj_obj_ptr(L->base+arg-1));
717+
lj_strfmt_putptr(sb, lj_obj_ptr(G(L), L->base+arg-1));
718718
break;
719719
default:
720720
lj_assertL(0, "bad string format type");

src/lj_api.c

+36-4
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ LUA_API void *lua_touserdata(lua_State *L, int idx)
608608
if (tvisudata(o))
609609
return uddata(udataV(o));
610610
else if (tvislightud(o))
611-
return lightudV(o);
611+
return lightudV(G(L), o);
612612
else
613613
return NULL;
614614
}
@@ -621,7 +621,7 @@ LUA_API lua_State *lua_tothread(lua_State *L, int idx)
621621

622622
LUA_API const void *lua_topointer(lua_State *L, int idx)
623623
{
624-
return lj_obj_ptr(index2adr(L, idx));
624+
return lj_obj_ptr(G(L), index2adr(L, idx));
625625
}
626626

627627
/* -- Stack setters (object creation) ------------------------------------- */
@@ -707,9 +707,38 @@ LUA_API void lua_pushboolean(lua_State *L, int b)
707707
incr_top(L);
708708
}
709709

710+
#if LJ_64
711+
static void *lightud_intern(lua_State *L, void *p)
712+
{
713+
global_State *g = G(L);
714+
uint64_t u = (uint64_t)p;
715+
uint32_t up = lightudup(u);
716+
uint32_t *segmap = mref(g->gc.lightudseg, uint32_t);
717+
MSize segnum = g->gc.lightudnum;
718+
if (segmap) {
719+
MSize seg;
720+
for (seg = 0; seg <= segnum; seg++)
721+
if (segmap[seg] == up) /* Fast path. */
722+
return (void *)(((uint64_t)seg << LJ_LIGHTUD_BITS_LO) | lightudlo(u));
723+
segnum++;
724+
}
725+
if (!((segnum-1) & segnum) && segnum != 1) {
726+
if (segnum >= (1 << LJ_LIGHTUD_BITS_SEG)) lj_err_msg(L, LJ_ERR_BADLU);
727+
lj_mem_reallocvec(L, segmap, segnum, segnum ? 2*segnum : 2u, uint32_t);
728+
setmref(g->gc.lightudseg, segmap);
729+
}
730+
g->gc.lightudnum = segnum;
731+
segmap[segnum] = up;
732+
return (void *)(((uint64_t)segnum << LJ_LIGHTUD_BITS_LO) | lightudlo(u));
733+
}
734+
#endif
735+
710736
LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
711737
{
712-
setlightudV(L->top, checklightudptr(L, p));
738+
#if LJ_64
739+
p = lightud_intern(L, p);
740+
#endif
741+
setrawlightudV(L->top, p);
713742
incr_top(L);
714743
}
715744

@@ -1149,7 +1178,10 @@ static TValue *cpcall(lua_State *L, lua_CFunction func, void *ud)
11491178
fn->c.f = func;
11501179
setfuncV(L, top++, fn);
11511180
if (LJ_FR2) setnilV(top++);
1152-
setlightudV(top++, checklightudptr(L, ud));
1181+
#if LJ_64
1182+
ud = lightud_intern(L, ud);
1183+
#endif
1184+
setrawlightudV(top++, ud);
11531185
cframe_nres(L->cframe) = 1+0; /* Zero results. */
11541186
L->top = top;
11551187
return top-1; /* Now call the newly allocated C function. */

src/lj_ccall.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ int lj_ccall_func(lua_State *L, GCcdata *cd)
11671167
lj_vm_ffi_call(&cc);
11681168
if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */
11691169
TValue tv;
1170-
setlightudV(&tv, (void *)cc.func);
1170+
tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000);
11711171
setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
11721172
}
11731173
ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */

src/lj_cconv.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
620620
if (ud->udtype == UDTYPE_IO_FILE)
621621
tmpptr = *(void **)tmpptr;
622622
} else if (tvislightud(o)) {
623-
tmpptr = lightudV(o);
623+
tmpptr = lightudV(cts->g, o);
624624
} else if (tvisfunc(o)) {
625625
void *p = lj_ccallback_new(cts, d, funcV(o));
626626
if (p) {

src/lj_crecord.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,7 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
646646
}
647647
} else if (tref_islightud(sp)) {
648648
#if LJ_64
649-
sp = emitir(IRT(IR_BAND, IRT_P64), sp,
650-
lj_ir_kint64(J, U64x(00007fff,ffffffff)));
649+
lj_trace_err(J, LJ_TRERR_NYICONV);
651650
#endif
652651
} else { /* NYI: tref_istab(sp). */
653652
IRType t;
@@ -1212,8 +1211,7 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
12121211
TRef tr;
12131212
TValue tv;
12141213
/* Check for blacklisted C functions that might call a callback. */
1215-
setlightudV(&tv,
1216-
cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4));
1214+
tv.u64 = ((uintptr_t)cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4) >> 2) | U64x(800000000, 00000000);
12171215
if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv)))
12181216
lj_trace_err(J, LJ_TRERR_BLACKL);
12191217
if (ctype_isvoid(ctr->info)) {

src/lj_dispatch.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ int luaJIT_setmode(lua_State *L, int idx, int mode)
295295
if (idx != 0) {
296296
cTValue *tv = idx > 0 ? L->base + (idx-1) : L->top + idx;
297297
if (tvislightud(tv))
298-
g->wrapf = (lua_CFunction)lightudV(tv);
298+
g->wrapf = (lua_CFunction)lightudV(g, tv);
299299
else
300300
return 0; /* Failed. */
301301
} else {

src/lj_ir.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,10 @@ void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir)
389389
case IR_KPRI: setpriV(tv, irt_toitype(ir->t)); break;
390390
case IR_KINT: setintV(tv, ir->i); break;
391391
case IR_KGC: setgcV(L, tv, ir_kgc(ir), irt_toitype(ir->t)); break;
392-
case IR_KPTR: case IR_KKPTR: setlightudV(tv, ir_kptr(ir)); break;
393-
case IR_KNULL: setlightudV(tv, NULL); break;
392+
case IR_KPTR: case IR_KKPTR:
393+
setnumV(tv, (lua_Number)(uintptr_t)ir_kptr(ir));
394+
break;
395+
case IR_KNULL: setintV(tv, 0); break;
394396
case IR_KNUM: setnumV(tv, ir_knum(ir)->n); break;
395397
#if LJ_HASFFI
396398
case IR_KINT64: {

src/lj_obj.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2)
3434
}
3535

3636
/* Return pointer to object or its object data. */
37-
const void * LJ_FASTCALL lj_obj_ptr(cTValue *o)
37+
const void * LJ_FASTCALL lj_obj_ptr(global_State *g, cTValue *o)
3838
{
39+
UNUSED(g);
3940
if (tvisudata(o))
4041
return uddata(udataV(o));
4142
else if (tvislightud(o))
42-
return lightudV(o);
43+
return lightudV(g, o);
4344
else if (LJ_HASFFI && tviscdata(o))
4445
return cdataptr(cdataV(o));
4546
else if (tvisgcv(o))

0 commit comments

Comments
 (0)