mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
completely untested, speculative mockup of fatuserdata
This commit is contained in:
parent
a6a2b86c9b
commit
fc82c8cec2
8 changed files with 63 additions and 10 deletions
|
@ -65,6 +65,7 @@ enum lua_Type
|
||||||
|
|
||||||
|
|
||||||
LUA_TLIGHTUSERDATA,
|
LUA_TLIGHTUSERDATA,
|
||||||
|
LUA_TFATUSERDATA,
|
||||||
LUA_TNUMBER,
|
LUA_TNUMBER,
|
||||||
LUA_TVECTOR,
|
LUA_TVECTOR,
|
||||||
|
|
||||||
|
@ -166,6 +167,7 @@ LUA_API void lua_pushcfunction(
|
||||||
lua_State* L, lua_CFunction fn, const char* debugname = NULL, int nup = 0, lua_Continuation cont = NULL);
|
lua_State* L, lua_CFunction fn, const char* debugname = NULL, int nup = 0, lua_Continuation cont = NULL);
|
||||||
LUA_API void lua_pushboolean(lua_State* L, int b);
|
LUA_API void lua_pushboolean(lua_State* L, int b);
|
||||||
LUA_API void lua_pushlightuserdata(lua_State* L, void* p);
|
LUA_API void lua_pushlightuserdata(lua_State* L, void* p);
|
||||||
|
LUA_API void lua_pushfatuserdata(lua_State* L);
|
||||||
LUA_API int lua_pushthread(lua_State* L);
|
LUA_API int lua_pushthread(lua_State* L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -102,6 +102,14 @@
|
||||||
/* maximum number of captures supported by pattern matching */
|
/* maximum number of captures supported by pattern matching */
|
||||||
#define LUA_MAXCAPTURES 32
|
#define LUA_MAXCAPTURES 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ LUAU_FATUSERDATA_WORDS defines the amount of extra space embedded in
|
||||||
|
@* fatuserdata values.
|
||||||
|
** This inflates every value in the VM, so use it carefully.
|
||||||
|
** At least 1 is required to store the `vector` value type.
|
||||||
|
*/
|
||||||
|
#define LUAU_FATUSERDATA_WORDS 1
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
/* Default number printing format and the string length limit */
|
/* Default number printing format and the string length limit */
|
||||||
|
|
|
@ -447,6 +447,8 @@ int lua_objlen(lua_State* L, int idx)
|
||||||
return tsvalue(o)->len;
|
return tsvalue(o)->len;
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
return uvalue(o)->len;
|
return uvalue(o)->len;
|
||||||
|
case LUA_TFATUSERDATA:
|
||||||
|
return LUAU_FATUSERDATA_WORDS;
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
return luaH_getn(hvalue(o));
|
return luaH_getn(hvalue(o));
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
|
@ -473,6 +475,7 @@ void* lua_touserdata(lua_State* L, int idx)
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
return uvalue(o)->data;
|
return uvalue(o)->data;
|
||||||
case LUA_TLIGHTUSERDATA:
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
case LUA_TFATUSERDATA:
|
||||||
return pvalue(o);
|
return pvalue(o);
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -625,6 +628,15 @@ void lua_pushlightuserdata(lua_State* L, void* p)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int UNINITIALIZED_FATUSERDATA[LUAU_FATUSERDATA_WORDS] = {};
|
||||||
|
|
||||||
|
void lua_pushfatuserdata(lua_State* L)
|
||||||
|
{
|
||||||
|
setmpvalue(L->top, 0, &UNINITIALIZED_FATUSERDATA);
|
||||||
|
api_incr_top(L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int lua_pushthread(lua_State* L)
|
int lua_pushthread(lua_State* L)
|
||||||
{
|
{
|
||||||
luaC_checkthreadsleep(L);
|
luaC_checkthreadsleep(L);
|
||||||
|
@ -740,6 +752,9 @@ int lua_getmetatable(lua_State* L, int objindex)
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
mt = uvalue(obj)->metatable;
|
mt = uvalue(obj)->metatable;
|
||||||
break;
|
break;
|
||||||
|
case LUA_TFATUSERDATA:
|
||||||
|
mt = (Table*)(mpvalue(obj));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mt = L->global->mt[ttype(obj)];
|
mt = L->global->mt[ttype(obj)];
|
||||||
break;
|
break;
|
||||||
|
@ -864,6 +879,13 @@ int lua_setmetatable(lua_State* L, int objindex)
|
||||||
luaC_objbarrier(L, uvalue(obj), mt);
|
luaC_objbarrier(L, uvalue(obj), mt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LUA_TFATUSERDATA:
|
||||||
|
{
|
||||||
|
mpvalue(obj) = (void*)mt;
|
||||||
|
if (mt)
|
||||||
|
luaC_objbarrier(L, uvalue(obj), mt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
L->global->mt[ttype(obj)] = mt;
|
L->global->mt[ttype(obj)] = mt;
|
||||||
|
|
|
@ -42,6 +42,8 @@ LUAU_FASTFLAG(LuauArrayBoundary)
|
||||||
checkconsistency(o); \
|
checkconsistency(o); \
|
||||||
if (iscollectable(o) && iswhite(gcvalue(o))) \
|
if (iscollectable(o) && iswhite(gcvalue(o))) \
|
||||||
reallymarkobject(g, gcvalue(o)); \
|
reallymarkobject(g, gcvalue(o)); \
|
||||||
|
else if (ttisfatuserdata(o) && mpvalue(o) && iswhite((GCObject*)mpvalue(o))) \
|
||||||
|
reallymarkobject(g, (GCObject*)mpvalue(o)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define markobject(g, t) \
|
#define markobject(g, t) \
|
||||||
|
|
|
@ -33,11 +33,16 @@
|
||||||
#define ABISWITCH(x64, ms32, gcc32) (sizeof(void*) == 8 ? x64 : ms32)
|
#define ABISWITCH(x64, ms32, gcc32) (sizeof(void*) == 8 ? x64 : ms32)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Padding makes it difficult to verify these statically, we'd basically be mirroring the compiler's layout algorithm
|
||||||
|
// So instead, only assert these when LUAU_FATUSERDATA_WORDS is 1, which is the go-to default/embedded configuration
|
||||||
|
#if LUAU_FATUSERDATA_WORDS == 1
|
||||||
static_assert(sizeof(TValue) == ABISWITCH(16, 16, 16), "size mismatch for value");
|
static_assert(sizeof(TValue) == ABISWITCH(16, 16, 16), "size mismatch for value");
|
||||||
|
static_assert(sizeof(LuaNode) == ABISWITCH(32, 32, 32), "size mismatch for table entry");
|
||||||
|
#endif
|
||||||
|
|
||||||
static_assert(offsetof(TString, data) == ABISWITCH(24, 20, 20), "size mismatch for string header");
|
static_assert(offsetof(TString, data) == ABISWITCH(24, 20, 20), "size mismatch for string header");
|
||||||
static_assert(offsetof(Udata, data) == ABISWITCH(24, 16, 16), "size mismatch for userdata header");
|
static_assert(offsetof(Udata, data) == ABISWITCH(24, 16, 16), "size mismatch for userdata header");
|
||||||
static_assert(sizeof(Table) == ABISWITCH(56, 36, 36), "size mismatch for table header");
|
static_assert(sizeof(Table) == ABISWITCH(56, 36, 36), "size mismatch for table header");
|
||||||
static_assert(sizeof(LuaNode) == ABISWITCH(32, 32, 32), "size mismatch for table entry");
|
|
||||||
|
|
||||||
const size_t kSizeClasses = LUA_SIZECLASSES;
|
const size_t kSizeClasses = LUA_SIZECLASSES;
|
||||||
const size_t kMaxSmallSize = 512;
|
const size_t kMaxSmallSize = 512;
|
||||||
|
|
|
@ -47,7 +47,7 @@ typedef union
|
||||||
typedef struct lua_TValue
|
typedef struct lua_TValue
|
||||||
{
|
{
|
||||||
Value value;
|
Value value;
|
||||||
int extra;
|
int extra[LUAU_FATUSERDATA_WORDS];
|
||||||
int tt;
|
int tt;
|
||||||
} TValue;
|
} TValue;
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ typedef struct lua_TValue
|
||||||
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
|
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
|
||||||
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
|
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
|
||||||
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
|
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
|
||||||
|
#define ttisfatuserdata(o) (ttype(o) == LUA_TFATUSERDATA)
|
||||||
#define ttisvector(o) (ttype(o) == LUA_TVECTOR)
|
#define ttisvector(o) (ttype(o) == LUA_TVECTOR)
|
||||||
#define ttisupval(o) (ttype(o) == LUA_TUPVAL)
|
#define ttisupval(o) (ttype(o) == LUA_TUPVAL)
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ typedef struct lua_TValue
|
||||||
#define ttype(o) ((o)->tt)
|
#define ttype(o) ((o)->tt)
|
||||||
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
|
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
|
||||||
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
|
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
|
||||||
|
#define mpvalue(o) check_exp(ttisfatuserdata(o), (o)->value.p)
|
||||||
#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
|
#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
|
||||||
#define vvalue(o) check_exp(ttisvector(o), (o)->value.v)
|
#define vvalue(o) check_exp(ttisvector(o), (o)->value.v)
|
||||||
#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
|
#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
|
||||||
|
@ -122,6 +124,14 @@ typedef struct lua_TValue
|
||||||
i_o->tt = LUA_TLIGHTUSERDATA; \
|
i_o->tt = LUA_TLIGHTUSERDATA; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define setmpvalue(obj, mt, data) \
|
||||||
|
{ \
|
||||||
|
TValue* i_o = (obj); \
|
||||||
|
i_o->value.p = (void*)(mt); \
|
||||||
|
memcpy(&i_o->extra, data, LUAU_FATUSERDATA_WORDS * sizeof(int)); \
|
||||||
|
i_o->tt = LUA_TLIGHTUSERDATA; \
|
||||||
|
}
|
||||||
|
|
||||||
#define setbvalue(obj, x) \
|
#define setbvalue(obj, x) \
|
||||||
{ \
|
{ \
|
||||||
TValue* i_o = (obj); \
|
TValue* i_o = (obj); \
|
||||||
|
@ -364,7 +374,7 @@ typedef struct Closure
|
||||||
typedef struct TKey
|
typedef struct TKey
|
||||||
{
|
{
|
||||||
::Value value;
|
::Value value;
|
||||||
int extra;
|
int extra[LUAU_FATUSERDATA_WORDS];
|
||||||
unsigned tt : 4;
|
unsigned tt : 4;
|
||||||
int next : 28; /* for chaining */
|
int next : 28; /* for chaining */
|
||||||
} TKey;
|
} TKey;
|
||||||
|
@ -381,7 +391,7 @@ typedef struct LuaNode
|
||||||
LuaNode* n_ = (node); \
|
LuaNode* n_ = (node); \
|
||||||
const TValue* i_o = (obj); \
|
const TValue* i_o = (obj); \
|
||||||
n_->key.value = i_o->value; \
|
n_->key.value = i_o->value; \
|
||||||
n_->key.extra = i_o->extra; \
|
memcpy(&n_->key.extra, &i_o->extra, LUAU_FATUSERDATA_WORDS * sizeof(int)); \
|
||||||
n_->key.tt = i_o->tt; \
|
n_->key.tt = i_o->tt; \
|
||||||
checkliveness(L->global, i_o); \
|
checkliveness(L->global, i_o); \
|
||||||
}
|
}
|
||||||
|
@ -392,7 +402,7 @@ typedef struct LuaNode
|
||||||
TValue* i_o = (obj); \
|
TValue* i_o = (obj); \
|
||||||
const LuaNode* n_ = (node); \
|
const LuaNode* n_ = (node); \
|
||||||
i_o->value = n_->key.value; \
|
i_o->value = n_->key.value; \
|
||||||
i_o->extra = n_->key.extra; \
|
memcpy(&i_o->extra, &n_->key.extra, LUAU_FATUSERDATA_WORDS * sizeof(int)); \
|
||||||
i_o->tt = n_->key.tt; \
|
i_o->tt = n_->key.tt; \
|
||||||
checkliveness(L->global, i_o); \
|
checkliveness(L->global, i_o); \
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,17 +32,17 @@ LUAU_FASTFLAGVARIABLE(LuauArrayBoundary, false)
|
||||||
|
|
||||||
static_assert(offsetof(LuaNode, val) == 0, "Unexpected Node memory layout, pointer cast in gval2slot is incorrect");
|
static_assert(offsetof(LuaNode, val) == 0, "Unexpected Node memory layout, pointer cast in gval2slot is incorrect");
|
||||||
// TKey is bitpacked for memory efficiency so we need to validate bit counts for worst case
|
// TKey is bitpacked for memory efficiency so we need to validate bit counts for worst case
|
||||||
static_assert(TKey{{NULL}, 0, LUA_TDEADKEY, 0}.tt == LUA_TDEADKEY, "not enough bits for tt");
|
static_assert(TKey{{NULL}, {}, LUA_TDEADKEY, 0}.tt == LUA_TDEADKEY, "not enough bits for tt");
|
||||||
static_assert(TKey{{NULL}, 0, LUA_TNIL, MAXSIZE - 1}.next == MAXSIZE - 1, "not enough bits for next");
|
static_assert(TKey{{NULL}, {}, LUA_TNIL, MAXSIZE - 1}.next == MAXSIZE - 1, "not enough bits for next");
|
||||||
static_assert(TKey{{NULL}, 0, LUA_TNIL, -(MAXSIZE - 1)}.next == -(MAXSIZE - 1), "not enough bits for next");
|
static_assert(TKey{{NULL}, {}, LUA_TNIL, -(MAXSIZE - 1)}.next == -(MAXSIZE - 1), "not enough bits for next");
|
||||||
|
|
||||||
// reset cache of absent metamethods, cache is updated in luaT_gettm
|
// reset cache of absent metamethods, cache is updated in luaT_gettm
|
||||||
#define invalidateTMcache(t) t->flags = 0
|
#define invalidateTMcache(t) t->flags = 0
|
||||||
|
|
||||||
// empty hash data points to dummynode so that we can always dereference it
|
// empty hash data points to dummynode so that we can always dereference it
|
||||||
const LuaNode luaH_dummynode = {
|
const LuaNode luaH_dummynode = {
|
||||||
{{NULL}, 0, LUA_TNIL}, /* value */
|
{{NULL}, {}, LUA_TNIL}, /* value */
|
||||||
{{NULL}, 0, LUA_TNIL, 0} /* key */
|
{{NULL}, {}, LUA_TNIL, 0} /* key */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define dummynode (&luaH_dummynode)
|
#define dummynode (&luaH_dummynode)
|
||||||
|
|
|
@ -16,6 +16,7 @@ const char* const luaT_typenames[] = {
|
||||||
"boolean",
|
"boolean",
|
||||||
|
|
||||||
|
|
||||||
|
"userdata",
|
||||||
"userdata",
|
"userdata",
|
||||||
"number",
|
"number",
|
||||||
"vector",
|
"vector",
|
||||||
|
@ -108,6 +109,9 @@ const TValue* luaT_gettmbyobj(lua_State* L, const TValue* o, TMS event)
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
mt = uvalue(o)->metatable;
|
mt = uvalue(o)->metatable;
|
||||||
break;
|
break;
|
||||||
|
case LUA_TFATUSERDATA:
|
||||||
|
mt = (Table*)(mpvalue(o));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mt = L->global->mt[ttype(o)];
|
mt = L->global->mt[ttype(o)];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue