mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-16 06:45:44 +08:00
Merge branch 'master' into merge
This commit is contained in:
commit
89090a16a6
@ -71,7 +71,7 @@ bool forgLoopTableIter(lua_State* L, Table* h, int index, TValue* ra)
|
||||
|
||||
if (!ttisnil(e))
|
||||
{
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)), LU_TAG_ITERATOR);
|
||||
setnvalue(ra + 3, double(index + 1));
|
||||
setobj2s(L, ra + 4, e);
|
||||
|
||||
@ -90,7 +90,7 @@ bool forgLoopTableIter(lua_State* L, Table* h, int index, TValue* ra)
|
||||
|
||||
if (!ttisnil(gval(n)))
|
||||
{
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)), LU_TAG_ITERATOR);
|
||||
getnodekey(L, ra + 3, n);
|
||||
setobj(L, ra + 4, gval(n));
|
||||
|
||||
@ -115,7 +115,7 @@ bool forgLoopNodeIter(lua_State* L, Table* h, int index, TValue* ra)
|
||||
|
||||
if (!ttisnil(gval(n)))
|
||||
{
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)), LU_TAG_ITERATOR);
|
||||
getnodekey(L, ra + 3, n);
|
||||
setobj(L, ra + 4, gval(n));
|
||||
|
||||
@ -697,7 +697,7 @@ const Instruction* executeFORGPREP(lua_State* L, const Instruction* pc, StkId ba
|
||||
{
|
||||
// set up registers for builtin iteration
|
||||
setobj2s(L, ra + 1, ra);
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)), LU_TAG_ITERATOR);
|
||||
setnilvalue(ra);
|
||||
}
|
||||
else
|
||||
|
@ -159,9 +159,11 @@ LUA_API const char* lua_namecallatom(lua_State* L, int* atom);
|
||||
LUA_API int lua_objlen(lua_State* L, int idx);
|
||||
LUA_API lua_CFunction lua_tocfunction(lua_State* L, int idx);
|
||||
LUA_API void* lua_tolightuserdata(lua_State* L, int idx);
|
||||
LUA_API void* lua_tolightuserdatatagged(lua_State* L, int idx, int tag);
|
||||
LUA_API void* lua_touserdata(lua_State* L, int idx);
|
||||
LUA_API void* lua_touserdatatagged(lua_State* L, int idx, int tag);
|
||||
LUA_API int lua_userdatatag(lua_State* L, int idx);
|
||||
LUA_API int lua_lightuserdatatag(lua_State* L, int idx);
|
||||
LUA_API lua_State* lua_tothread(lua_State* L, int idx);
|
||||
LUA_API void* lua_tobuffer(lua_State* L, int idx, size_t* len);
|
||||
LUA_API const void* lua_topointer(lua_State* L, int idx);
|
||||
@ -186,7 +188,7 @@ LUA_API void lua_pushcclosurek(lua_State* L, lua_CFunction fn, const char* debug
|
||||
LUA_API void lua_pushboolean(lua_State* L, int b);
|
||||
LUA_API int lua_pushthread(lua_State* L);
|
||||
|
||||
LUA_API void lua_pushlightuserdata(lua_State* L, void* p);
|
||||
LUA_API void lua_pushlightuserdatatagged(lua_State* L, void* p, int tag);
|
||||
LUA_API void* lua_newuserdatatagged(lua_State* L, size_t sz, int tag);
|
||||
LUA_API void* lua_newuserdatadtor(lua_State* L, size_t sz, void (*dtor)(void*));
|
||||
|
||||
@ -323,6 +325,9 @@ typedef void (*lua_Destructor)(lua_State* L, void* userdata);
|
||||
LUA_API void lua_setuserdatadtor(lua_State* L, int tag, lua_Destructor dtor);
|
||||
LUA_API lua_Destructor lua_getuserdatadtor(lua_State* L, int tag);
|
||||
|
||||
LUA_API void lua_setlightuserdataname(lua_State* L, int tag, const char* name);
|
||||
LUA_API const char* lua_getlightuserdataname(lua_State* L, int tag);
|
||||
|
||||
LUA_API void lua_clonefunction(lua_State* L, int idx);
|
||||
|
||||
LUA_API void lua_cleartable(lua_State* L, int idx);
|
||||
@ -370,6 +375,7 @@ LUA_API void lua_unref(lua_State* L, int ref);
|
||||
#define lua_pushliteral(L, s) lua_pushlstring(L, "" s, (sizeof(s) / sizeof(char)) - 1)
|
||||
#define lua_pushcfunction(L, fn, debugname) lua_pushcclosurek(L, fn, debugname, 0, NULL)
|
||||
#define lua_pushcclosure(L, fn, debugname, nup) lua_pushcclosurek(L, fn, debugname, nup, NULL)
|
||||
#define lua_pushlightuserdata(L, p) lua_pushlightuserdatatagged(L, p, 0)
|
||||
|
||||
#define lua_setglobal(L, s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
|
||||
#define lua_getglobal(L, s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
|
||||
|
@ -101,6 +101,11 @@
|
||||
#define LUA_UTAG_LIMIT 128
|
||||
#endif
|
||||
|
||||
// number of valid Lua lightuserdata tags
|
||||
#ifndef LUA_LUTAG_LIMIT
|
||||
#define LUA_LUTAG_LIMIT 128
|
||||
#endif
|
||||
|
||||
// upper bound for number of size classes used by page allocator
|
||||
#ifndef LUA_SIZECLASSES
|
||||
#define LUA_SIZECLASSES 32
|
||||
|
@ -505,6 +505,12 @@ void* lua_tolightuserdata(lua_State* L, int idx)
|
||||
return (!ttislightuserdata(o)) ? NULL : pvalue(o);
|
||||
}
|
||||
|
||||
void* lua_tolightuserdatatagged(lua_State* L, int idx, int tag)
|
||||
{
|
||||
StkId o = index2addr(L, idx);
|
||||
return (!ttislightuserdata(o) || lightuserdatatag(o) != tag) ? NULL : pvalue(o);
|
||||
}
|
||||
|
||||
void* lua_touserdata(lua_State* L, int idx)
|
||||
{
|
||||
StkId o = index2addr(L, idx);
|
||||
@ -530,6 +536,14 @@ int lua_userdatatag(lua_State* L, int idx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lua_lightuserdatatag(lua_State* L, int idx)
|
||||
{
|
||||
StkId o = index2addr(L, idx);
|
||||
if (ttislightuserdata(o))
|
||||
return lightuserdatatag(o);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lua_State* lua_tothread(lua_State* L, int idx)
|
||||
{
|
||||
StkId o = index2addr(L, idx);
|
||||
@ -665,9 +679,10 @@ void lua_pushboolean(lua_State* L, int b)
|
||||
api_incr_top(L);
|
||||
}
|
||||
|
||||
void lua_pushlightuserdata(lua_State* L, void* p)
|
||||
void lua_pushlightuserdatatagged(lua_State* L, void* p, int tag)
|
||||
{
|
||||
setpvalue(L->top, p);
|
||||
api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT);
|
||||
setpvalue(L->top, p, tag);
|
||||
api_incr_top(L);
|
||||
}
|
||||
|
||||
@ -1412,6 +1427,24 @@ lua_Destructor lua_getuserdatadtor(lua_State* L, int tag)
|
||||
return L->global->udatagc[tag];
|
||||
}
|
||||
|
||||
void lua_setlightuserdataname(lua_State* L, int tag, const char* name)
|
||||
{
|
||||
api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT);
|
||||
api_check(L, !L->global->lightuserdataname[tag]); // renaming not supported
|
||||
if (!L->global->lightuserdataname[tag])
|
||||
{
|
||||
L->global->lightuserdataname[tag] = luaS_new(L, name);
|
||||
luaS_fix(L->global->lightuserdataname[tag]); // never collect these names
|
||||
}
|
||||
}
|
||||
|
||||
const char* lua_getlightuserdataname(lua_State* L, int tag)
|
||||
{
|
||||
api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT);
|
||||
const TString* name = L->global->lightuserdataname[tag];
|
||||
return name ? getstr(name) : nullptr;
|
||||
}
|
||||
|
||||
void lua_clonefunction(lua_State* L, int idx)
|
||||
{
|
||||
luaC_checkGC(L);
|
||||
|
@ -48,7 +48,7 @@ int luaO_rawequalObj(const TValue* t1, const TValue* t2)
|
||||
case LUA_TBOOLEAN:
|
||||
return bvalue(t1) == bvalue(t2); // boolean true must be 1 !!
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return pvalue(t1) == pvalue(t2);
|
||||
return pvalue(t1) == pvalue(t2) && (!FFlag::TaggedLuData || lightuserdatatag(t1) == lightuserdatatag(t2));
|
||||
default:
|
||||
LUAU_ASSERT(iscollectable(t1));
|
||||
return gcvalue(t1) == gcvalue(t2);
|
||||
@ -71,7 +71,7 @@ int luaO_rawequalKey(const TKey* t1, const TValue* t2)
|
||||
case LUA_TBOOLEAN:
|
||||
return bvalue(t1) == bvalue(t2); // boolean true must be 1 !!
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return pvalue(t1) == pvalue(t2);
|
||||
return pvalue(t1) == pvalue(t2) && (!FFlag::TaggedLuData || lightuserdatatag(t1) == lightuserdatatag(t2));
|
||||
default:
|
||||
LUAU_ASSERT(iscollectable(t1));
|
||||
return gcvalue(t1) == gcvalue(t2);
|
||||
|
@ -80,6 +80,11 @@ typedef struct lua_TValue
|
||||
|
||||
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
|
||||
|
||||
#define lightuserdatatag(o) check_exp(ttislightuserdata(o), (o)->extra[0])
|
||||
|
||||
// Internal tags used by the VM
|
||||
#define LU_TAG_ITERATOR LUA_UTAG_LIMIT
|
||||
|
||||
/*
|
||||
** for internal debug only
|
||||
*/
|
||||
@ -120,10 +125,11 @@ typedef struct lua_TValue
|
||||
}
|
||||
#endif
|
||||
|
||||
#define setpvalue(obj, x) \
|
||||
#define setpvalue(obj, x, tag) \
|
||||
{ \
|
||||
TValue* i_o = (obj); \
|
||||
i_o->value.p = (x); \
|
||||
i_o->extra[0] = (tag); \
|
||||
i_o->tt = LUA_TLIGHTUSERDATA; \
|
||||
}
|
||||
|
||||
@ -492,3 +498,5 @@ LUAI_FUNC int luaO_str2d(const char* s, double* result);
|
||||
LUAI_FUNC const char* luaO_pushvfstring(lua_State* L, const char* fmt, va_list argp);
|
||||
LUAI_FUNC const char* luaO_pushfstring(lua_State* L, const char* fmt, ...);
|
||||
LUAI_FUNC const char* luaO_chunkid(char* buf, size_t buflen, const char* source, size_t srclen);
|
||||
|
||||
LUAU_FASTFLAG(TaggedLuData)
|
||||
|
@ -210,6 +210,8 @@ lua_State* lua_newstate(lua_Alloc f, void* ud)
|
||||
g->mt[i] = NULL;
|
||||
for (i = 0; i < LUA_UTAG_LIMIT; i++)
|
||||
g->udatagc[i] = NULL;
|
||||
for (i = 0; i < LUA_LUTAG_LIMIT; i++)
|
||||
g->lightuserdataname[i] = NULL;
|
||||
for (i = 0; i < LUA_MEMORY_CATEGORIES; i++)
|
||||
g->memcatbytes[i] = 0;
|
||||
|
||||
|
@ -214,6 +214,8 @@ typedef struct global_State
|
||||
|
||||
void (*udatagc[LUA_UTAG_LIMIT])(lua_State*, void*); // for each userdata tag, a gc callback to be called immediately before freeing memory
|
||||
|
||||
TString* lightuserdataname[LUA_LUTAG_LIMIT]; // names for tagged lightuserdata
|
||||
|
||||
GCStats gcstats;
|
||||
|
||||
#ifdef LUAI_GCMETRICS
|
||||
|
@ -129,6 +129,18 @@ const TString* luaT_objtypenamestr(lua_State* L, const TValue* o)
|
||||
if (ttisstring(type))
|
||||
return tsvalue(type);
|
||||
}
|
||||
else if (FFlag::TaggedLuData && ttislightuserdata(o))
|
||||
{
|
||||
int tag = lightuserdatatag(o);
|
||||
|
||||
if (unsigned(tag) < LUA_LUTAG_LIMIT)
|
||||
{
|
||||
const TString* name = L->global->lightuserdataname[tag];
|
||||
|
||||
if (name)
|
||||
return name;
|
||||
}
|
||||
}
|
||||
else if (Table* mt = L->global->mt[ttype(o)])
|
||||
{
|
||||
const TValue* type = luaH_getstr(mt, L->global->tmname[TM_TYPE]);
|
||||
|
@ -135,6 +135,8 @@
|
||||
// Does VM support native execution via ExecutionCallbacks? We mostly assume it does but keep the define to make it easy to quantify the cost.
|
||||
#define VM_HAS_NATIVE 1
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(TaggedLuData, false)
|
||||
|
||||
LUAU_NOINLINE void luau_callhook(lua_State* L, lua_Hook hook, void* userdata)
|
||||
{
|
||||
ptrdiff_t base = savestack(L, L->base);
|
||||
@ -1110,7 +1112,7 @@ reentry:
|
||||
VM_NEXT();
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
pc += pvalue(ra) == pvalue(rb) ? LUAU_INSN_D(insn) : 1;
|
||||
pc += (pvalue(ra) == pvalue(rb) && (!FFlag::TaggedLuData || lightuserdatatag(ra) == lightuserdatatag(rb))) ? LUAU_INSN_D(insn) : 1;
|
||||
LUAU_ASSERT(unsigned(pc - cl->l.p->code) < unsigned(cl->l.p->sizecode));
|
||||
VM_NEXT();
|
||||
|
||||
@ -1225,7 +1227,7 @@ reentry:
|
||||
VM_NEXT();
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
pc += pvalue(ra) != pvalue(rb) ? LUAU_INSN_D(insn) : 1;
|
||||
pc += (pvalue(ra) != pvalue(rb) || (FFlag::TaggedLuData && lightuserdatatag(ra) != lightuserdatatag(rb))) ? LUAU_INSN_D(insn) : 1;
|
||||
LUAU_ASSERT(unsigned(pc - cl->l.p->code) < unsigned(cl->l.p->sizecode));
|
||||
VM_NEXT();
|
||||
|
||||
@ -2296,7 +2298,7 @@ reentry:
|
||||
{
|
||||
// set up registers for builtin iteration
|
||||
setobj2s(L, ra + 1, ra);
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)), LU_TAG_ITERATOR);
|
||||
setnilvalue(ra);
|
||||
}
|
||||
else
|
||||
@ -2348,7 +2350,7 @@ reentry:
|
||||
|
||||
if (!ttisnil(e))
|
||||
{
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)), LU_TAG_ITERATOR);
|
||||
setnvalue(ra + 3, double(index + 1));
|
||||
setobj2s(L, ra + 4, e);
|
||||
|
||||
@ -2369,7 +2371,7 @@ reentry:
|
||||
|
||||
if (!ttisnil(gval(n)))
|
||||
{
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(index + 1)), LU_TAG_ITERATOR);
|
||||
getnodekey(L, ra + 3, n);
|
||||
setobj2s(L, ra + 4, gval(n));
|
||||
|
||||
@ -2421,7 +2423,7 @@ reentry:
|
||||
{
|
||||
setnilvalue(ra);
|
||||
// ra+1 is already the table
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)), LU_TAG_ITERATOR);
|
||||
}
|
||||
else if (!ttisfunction(ra))
|
||||
{
|
||||
@ -2450,7 +2452,7 @@ reentry:
|
||||
{
|
||||
setnilvalue(ra);
|
||||
// ra+1 is already the table
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)));
|
||||
setpvalue(ra + 2, reinterpret_cast<void*>(uintptr_t(0)), LU_TAG_ITERATOR);
|
||||
}
|
||||
else if (!ttisfunction(ra))
|
||||
{
|
||||
|
@ -288,7 +288,7 @@ int luaV_equalval(lua_State* L, const TValue* t1, const TValue* t2)
|
||||
case LUA_TBOOLEAN:
|
||||
return bvalue(t1) == bvalue(t2); // true must be 1 !!
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return pvalue(t1) == pvalue(t2);
|
||||
return pvalue(t1) == pvalue(t2) && (!FFlag::TaggedLuData || lightuserdatatag(t1) == lightuserdatatag(t2));
|
||||
case LUA_TUSERDATA:
|
||||
{
|
||||
tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ);
|
||||
|
@ -32,6 +32,7 @@ LUAU_FASTFLAG(LuauBufferDefinitions);
|
||||
LUAU_FASTFLAG(LuauCodeGenFixByteLower);
|
||||
LUAU_FASTFLAG(LuauCompileBufferAnnotation);
|
||||
LUAU_FASTFLAG(LuauLoopInterruptFix);
|
||||
LUAU_FASTFLAG(TaggedLuData);
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauStricterUtf8);
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit);
|
||||
|
||||
@ -1700,6 +1701,32 @@ TEST_CASE("UserdataApi")
|
||||
CHECK(dtorhits == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("LightuserdataApi")
|
||||
{
|
||||
ScopedFastFlag taggedLuData{FFlag::TaggedLuData, true};
|
||||
|
||||
StateRef globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
void* value = (void*)0x12345678;
|
||||
|
||||
lua_pushlightuserdatatagged(L, value, 1);
|
||||
CHECK(lua_lightuserdatatag(L, -1) == 1);
|
||||
CHECK(lua_tolightuserdatatagged(L, -1, 0) == nullptr);
|
||||
CHECK(lua_tolightuserdatatagged(L, -1, 1) == value);
|
||||
|
||||
lua_setlightuserdataname(L, 1, "id");
|
||||
CHECK(!lua_getlightuserdataname(L, 0));
|
||||
CHECK(strcmp(lua_getlightuserdataname(L, 1), "id") == 0);
|
||||
CHECK(strcmp(luaL_typename(L, -1), "id") == 0);
|
||||
|
||||
lua_pushlightuserdatatagged(L, value, 0);
|
||||
lua_pushlightuserdatatagged(L, value, 1);
|
||||
CHECK(lua_rawequal(L, -1, -2) == 0);
|
||||
|
||||
globalState.reset();
|
||||
}
|
||||
|
||||
TEST_CASE("Iter")
|
||||
{
|
||||
runConformance("iter.lua");
|
||||
|
Loading…
Reference in New Issue
Block a user