luau/VM/src/ltm.cpp
Junseo Yoo 5e0779fd57
Sync to upstream/release/636 (#1346)
# What's Changed?

- Telemetry support for usage of any type in old/new solver
- Bug fixes and flag removals with the new solver

## New Solver

- Fixed constraint ordering bug to infer types more accurately
- Improved inferring a call to `setmetatable()`

## VM

- Restored global metatable lookup for `typeof` on lightuserdata to fix
unintentional API change (Fixes #1335)

---
### Internal Contributors

Co-authored-by: Aaron Weiss <aaronweiss@roblox.com>
Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Dibri Nsofor <dnsofor@roblox.com>
Co-authored-by: Jeremy Yoo <jyoo@roblox.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>

---------

Co-authored-by: Aaron Weiss <aaronweiss@roblox.com>
Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Vighnesh <vvijay@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: David Cope <dcope@roblox.com>
Co-authored-by: Lily Brown <lbrown@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-07-26 10:47:49 -07:00

201 lines
5.0 KiB
C++

// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
#include "ltm.h"
#include "lstate.h"
#include "lstring.h"
#include "ludata.h"
#include "ltable.h"
#include "lgc.h"
#include <string.h>
LUAU_FASTFLAGVARIABLE(LuauPreserveLudataRenaming, false)
// clang-format off
const char* const luaT_typenames[] = {
// ORDER TYPE
"nil",
"boolean",
"userdata",
"number",
"vector",
"string",
"table",
"function",
"userdata",
"thread",
"buffer",
};
const char* const luaT_eventname[] = {
// ORDER TM
"__index",
"__newindex",
"__mode",
"__namecall",
"__call",
"__iter",
"__len",
"__eq",
"__add",
"__sub",
"__mul",
"__div",
"__idiv",
"__mod",
"__pow",
"__unm",
"__lt",
"__le",
"__concat",
"__type",
"__metatable",
};
// clang-format on
static_assert(sizeof(luaT_typenames) / sizeof(luaT_typenames[0]) == LUA_T_COUNT, "luaT_typenames size mismatch");
static_assert(sizeof(luaT_eventname) / sizeof(luaT_eventname[0]) == TM_N, "luaT_eventname size mismatch");
static_assert(TM_EQ < 8, "fasttm optimization stores a bitfield with metamethods in a byte");
void luaT_init(lua_State* L)
{
int i;
for (i = 0; i < LUA_T_COUNT; i++)
{
L->global->ttname[i] = luaS_new(L, luaT_typenames[i]);
luaS_fix(L->global->ttname[i]); // never collect these names
}
for (i = 0; i < TM_N; i++)
{
L->global->tmname[i] = luaS_new(L, luaT_eventname[i]);
luaS_fix(L->global->tmname[i]); // never collect these names
}
}
/*
** function to be used with macro "fasttm": optimized for absence of
** tag methods.
*/
const TValue* luaT_gettm(Table* events, TMS event, TString* ename)
{
const TValue* tm = luaH_getstr(events, ename);
LUAU_ASSERT(event <= TM_EQ);
if (ttisnil(tm))
{ // no tag method?
events->tmcache |= cast_byte(1u << event); // cache this fact
return NULL;
}
else
return tm;
}
const TValue* luaT_gettmbyobj(lua_State* L, const TValue* o, TMS event)
{
/*
NB: Tag-methods were replaced by meta-methods in Lua 5.0, but the
old names are still around (this function, for example).
*/
Table* mt;
switch (ttype(o))
{
case LUA_TTABLE:
mt = hvalue(o)->metatable;
break;
case LUA_TUSERDATA:
mt = uvalue(o)->metatable;
break;
default:
mt = L->global->mt[ttype(o)];
}
return (mt ? luaH_getstr(mt, L->global->tmname[event]) : luaO_nilobject);
}
const TString* luaT_objtypenamestr(lua_State* L, const TValue* o)
{
if (FFlag::LuauPreserveLudataRenaming)
{
// Userdata created by the environment can have a custom type name set in the individual metatable
// If there is no custom name, 'userdata' is returned
if (ttisuserdata(o) && uvalue(o)->tag != UTAG_PROXY && uvalue(o)->metatable)
{
const TValue* type = luaH_getstr(uvalue(o)->metatable, L->global->tmname[TM_TYPE]);
if (ttisstring(type))
return tsvalue(type);
return L->global->ttname[ttype(o)];
}
// Tagged lightuserdata can be named using lua_setlightuserdataname
if (ttislightuserdata(o))
{
int tag = lightuserdatatag(o);
if (unsigned(tag) < LUA_LUTAG_LIMIT)
{
if (const TString* name = L->global->lightuserdataname[tag])
return name;
}
}
// For all types except userdata and table, a global metatable can be set with a global name override
if (Table* mt = L->global->mt[ttype(o)])
{
const TValue* type = luaH_getstr(mt, L->global->tmname[TM_TYPE]);
if (ttisstring(type))
return tsvalue(type);
}
return L->global->ttname[ttype(o)];
}
else
{
if (ttisuserdata(o) && uvalue(o)->tag != UTAG_PROXY && uvalue(o)->metatable)
{
const TValue* type = luaH_getstr(uvalue(o)->metatable, L->global->tmname[TM_TYPE]);
if (ttisstring(type))
return tsvalue(type);
}
else if (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]);
if (ttisstring(type))
return tsvalue(type);
}
return L->global->ttname[ttype(o)];
}
}
const char* luaT_objtypename(lua_State* L, const TValue* o)
{
return getstr(luaT_objtypenamestr(L, o));
}