luau/VM/src/lobject.h

504 lines
12 KiB
C
Raw Normal View History

// 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
#pragma once
#include "lua.h"
#include "lcommon.h"
/*
** Union of all collectible objects
*/
typedef union GCObject GCObject;
/*
** Common Header for all collectible objects (in macro form, to be included in other objects)
*/
// clang-format off
#define CommonHeader \
uint8_t tt; uint8_t marked; uint8_t memcat
// clang-format on
/*
** Common header in struct form
*/
typedef struct GCheader
{
CommonHeader;
} GCheader;
/*
** Union of all Lua values
*/
typedef union
{
GCObject* gc;
void* p;
double n;
int b;
float v[2]; // v[0], v[1] live here; v[2] lives in TValue::extra
} Value;
/*
** Tagged Values
*/
typedef struct lua_TValue
{
Value value;
int extra[LUA_EXTRA_SIZE];
int tt;
} TValue;
2022-08-04 15:35:33 -07:00
// Macros to test type
#define ttisnil(o) (ttype(o) == LUA_TNIL)
#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
#define ttisstring(o) (ttype(o) == LUA_TSTRING)
#define ttistable(o) (ttype(o) == LUA_TTABLE)
#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-20 18:10:30 -07:00
#define ttisbuffer(o) (ttype(o) == LUA_TBUFFER)
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
#define ttisvector(o) (ttype(o) == LUA_TVECTOR)
#define ttisupval(o) (ttype(o) == LUA_TUPVAL)
2022-08-04 15:35:33 -07:00
// Macros to access values
#define ttype(o) ((o)->tt)
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
#define vvalue(o) check_exp(ttisvector(o), (o)->value.v)
#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
#define uvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u)
#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl)
#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h)
#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th)
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-20 18:10:30 -07:00
#define bufvalue(o) check_exp(ttisbuffer(o), &(o)->value.gc->buf)
#define upvalue(o) check_exp(ttisupval(o), &(o)->value.gc->uv)
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
Add tagged lightuserdata (#1087) This change adds support for tagged lightuserdata and optional custom typenames for lightuserdata. Background: Lightuserdata is an efficient representation for many kinds of unmanaged handles and resources in a game engine. However, currently the VM only supports one kind of lightuserdata, which makes it problematic in practice. For example, it's not possible to distinguish between different kinds of lightuserdata in Lua bindings, which can lead to unsafe practices and even crashes when a wrong kind of lightuserdata is passed to a binding function. Tagged lightuserdata work similarly to tagged userdata, i.e. they allow checking the tag quickly using lua_tolightuserdatatagged (or lua_lightuserdatatag). The tag is stored in the 'extra' field of TValue so it will add no cost to the (untagged) lightuserdata type. Alternatives would be to use full userdata values or use bitpacking to embed type information into lightuserdata on application level. Unfortunately these options are not that great in practice: full userdata have major performance implications and bitpacking fails in cases where full 64 bits are already used (e.g. pointers or 64-bit hashes). Lightuserdata names are not strictly necessary but they are rather convenient when debugging Lua code. More precise error messages and tostring returning more specific typename are useful to have in practice (e.g. "resource" or "entity" instead of the more generic "userdata"). Impl note: I did not add support for renaming tags in lua_setlightuserdataname as I'm not sure if it's possible to free fixed strings. If it's simple enough, maybe we should allow renaming (although I can't think of a specific need for it)? --------- Co-authored-by: Petri Häkkinen <petrih@rmd.remedy.fi>
2023-12-15 01:05:51 +02:00
#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
*/
#define checkconsistency(obj) LUAU_ASSERT(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
#define checkliveness(g, obj) LUAU_ASSERT(!iscollectable(obj) || ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
2022-08-04 15:35:33 -07:00
// Macros to set values
#define setnilvalue(obj) ((obj)->tt = LUA_TNIL)
#define setnvalue(obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.n = (x); \
i_o->tt = LUA_TNUMBER; \
}
#if LUA_VECTOR_SIZE == 4
#define setvvalue(obj, x, y, z, w) \
{ \
TValue* i_o = (obj); \
float* i_v = i_o->value.v; \
i_v[0] = (x); \
i_v[1] = (y); \
i_v[2] = (z); \
i_v[3] = (w); \
i_o->tt = LUA_TVECTOR; \
}
#else
#define setvvalue(obj, x, y, z, w) \
{ \
TValue* i_o = (obj); \
float* i_v = i_o->value.v; \
i_v[0] = (x); \
i_v[1] = (y); \
i_v[2] = (z); \
i_o->tt = LUA_TVECTOR; \
}
#endif
Add tagged lightuserdata (#1087) This change adds support for tagged lightuserdata and optional custom typenames for lightuserdata. Background: Lightuserdata is an efficient representation for many kinds of unmanaged handles and resources in a game engine. However, currently the VM only supports one kind of lightuserdata, which makes it problematic in practice. For example, it's not possible to distinguish between different kinds of lightuserdata in Lua bindings, which can lead to unsafe practices and even crashes when a wrong kind of lightuserdata is passed to a binding function. Tagged lightuserdata work similarly to tagged userdata, i.e. they allow checking the tag quickly using lua_tolightuserdatatagged (or lua_lightuserdatatag). The tag is stored in the 'extra' field of TValue so it will add no cost to the (untagged) lightuserdata type. Alternatives would be to use full userdata values or use bitpacking to embed type information into lightuserdata on application level. Unfortunately these options are not that great in practice: full userdata have major performance implications and bitpacking fails in cases where full 64 bits are already used (e.g. pointers or 64-bit hashes). Lightuserdata names are not strictly necessary but they are rather convenient when debugging Lua code. More precise error messages and tostring returning more specific typename are useful to have in practice (e.g. "resource" or "entity" instead of the more generic "userdata"). Impl note: I did not add support for renaming tags in lua_setlightuserdataname as I'm not sure if it's possible to free fixed strings. If it's simple enough, maybe we should allow renaming (although I can't think of a specific need for it)? --------- Co-authored-by: Petri Häkkinen <petrih@rmd.remedy.fi>
2023-12-15 01:05:51 +02:00
#define setpvalue(obj, x, tag) \
{ \
TValue* i_o = (obj); \
i_o->value.p = (x); \
Add tagged lightuserdata (#1087) This change adds support for tagged lightuserdata and optional custom typenames for lightuserdata. Background: Lightuserdata is an efficient representation for many kinds of unmanaged handles and resources in a game engine. However, currently the VM only supports one kind of lightuserdata, which makes it problematic in practice. For example, it's not possible to distinguish between different kinds of lightuserdata in Lua bindings, which can lead to unsafe practices and even crashes when a wrong kind of lightuserdata is passed to a binding function. Tagged lightuserdata work similarly to tagged userdata, i.e. they allow checking the tag quickly using lua_tolightuserdatatagged (or lua_lightuserdatatag). The tag is stored in the 'extra' field of TValue so it will add no cost to the (untagged) lightuserdata type. Alternatives would be to use full userdata values or use bitpacking to embed type information into lightuserdata on application level. Unfortunately these options are not that great in practice: full userdata have major performance implications and bitpacking fails in cases where full 64 bits are already used (e.g. pointers or 64-bit hashes). Lightuserdata names are not strictly necessary but they are rather convenient when debugging Lua code. More precise error messages and tostring returning more specific typename are useful to have in practice (e.g. "resource" or "entity" instead of the more generic "userdata"). Impl note: I did not add support for renaming tags in lua_setlightuserdataname as I'm not sure if it's possible to free fixed strings. If it's simple enough, maybe we should allow renaming (although I can't think of a specific need for it)? --------- Co-authored-by: Petri Häkkinen <petrih@rmd.remedy.fi>
2023-12-15 01:05:51 +02:00
i_o->extra[0] = (tag); \
i_o->tt = LUA_TLIGHTUSERDATA; \
}
#define setbvalue(obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.b = (x); \
i_o->tt = LUA_TBOOLEAN; \
}
#define setsvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TSTRING; \
checkliveness(L->global, i_o); \
}
#define setuvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TUSERDATA; \
checkliveness(L->global, i_o); \
}
#define setthvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TTHREAD; \
checkliveness(L->global, i_o); \
}
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-20 18:10:30 -07:00
#define setbufvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TBUFFER; \
checkliveness(L->global, i_o); \
}
#define setclvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TFUNCTION; \
checkliveness(L->global, i_o); \
}
#define sethvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TTABLE; \
checkliveness(L->global, i_o); \
}
#define setptvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TPROTO; \
checkliveness(L->global, i_o); \
}
#define setupvalue(L, obj, x) \
{ \
TValue* i_o = (obj); \
i_o->value.gc = cast_to(GCObject*, (x)); \
i_o->tt = LUA_TUPVAL; \
checkliveness(L->global, i_o); \
}
#define setobj(L, obj1, obj2) \
{ \
const TValue* o2 = (obj2); \
TValue* o1 = (obj1); \
*o1 = *o2; \
checkliveness(L->global, o1); \
}
/*
** different types of sets, according to destination
*/
// to stack
#define setobj2s setobj
// from table to same table (no barrier)
#define setobjt2t setobj
// to table (needs barrier)
#define setobj2t setobj
// to new object (no barrier)
#define setobj2n setobj
#define setttype(obj, tt) (ttype(obj) = (tt))
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
2022-08-04 15:35:33 -07:00
typedef TValue* StkId; // index to stack elements
/*
** String headers for string table
*/
typedef struct TString
{
CommonHeader;
// 1 byte padding
int16_t atom;
// 2 byte padding
TString* next; // next string in the hash table bucket
2022-02-24 15:53:37 -08:00
unsigned int hash;
unsigned int len;
char data[1]; // string data is allocated right after the header
} TString;
#define getstr(ts) (ts)->data
#define svalue(o) getstr(tsvalue(o))
typedef struct Udata
{
CommonHeader;
uint8_t tag;
int len;
struct Table* metatable;
union
{
char data[1]; // userdata is allocated right after the header
L_Umaxalign dummy; // ensures maximum alignment for data
};
} Udata;
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-20 18:10:30 -07:00
typedef struct Buffer
{
CommonHeader;
unsigned int len;
union
{
char data[1]; // buffer is allocated right after the header
L_Umaxalign dummy; // ensures maximum alignment for data
};
} Buffer;
/*
** Function Prototypes
*/
// clang-format off
typedef struct Proto
{
CommonHeader;
uint8_t nups; // number of upvalues
uint8_t numparams;
uint8_t is_vararg;
uint8_t maxstacksize;
uint8_t flags;
2022-08-04 15:35:33 -07:00
TValue* k; // constants used by the function
Instruction* code; // function bytecode
struct Proto** p; // functions defined inside the function
const Instruction* codeentry;
void* execdata;
uintptr_t exectarget;
2022-08-04 15:35:33 -07:00
uint8_t* lineinfo; // for each instruction, line number as a delta from baseline
int* abslineinfo; // baseline line info, one entry for each 1<<linegaplog2 instructions; allocated after lineinfo
struct LocVar* locvars; // information about local variables
TString** upvalues; // upvalue names
TString* source;
TString* debugname;
uint8_t* debuginsn; // a copy of code[] array with just opcodes
uint8_t* typeinfo;
Sync to upstream/release/588 (#992) Type checker/autocomplete: * `Luau::autocomplete` no longer performs typechecking internally, make sure to run `Frontend::check` before performing autocomplete requests * Autocomplete string suggestions without "" are now only suggested inside the "" * Autocomplete suggestions now include `function (anonymous autofilled)` key with a full suggestion for the function expression (with arguments included) stored in `AutocompleteEntry::insertText` * `AutocompleteEntry::indexedWithSelf` is provided for function call suggestions made with `:` * Cyclic modules now see each other type exports as `any` to prevent memory use-after-free (similar to module return type) Runtime: * Updated inline/loop unroll cost model to better handle assignments (Fixes https://github.com/Roblox/luau/issues/978) * `math.noise` speed was improved by ~30% * `table.concat` speed was improved by ~5-7% * `tonumber` and `tostring` now have fastcall paths that execute ~1.5x and ~2.5x faster respectively (fixes #777) * Fixed crash in `luaL_typename` when index refers to a non-existing value * Fixed potential out of memory scenario when using `string.sub` or `string.char` in a loop * Fixed behavior of some fastcall builtins when called without arguments under -O2 to match original functions * Support for native code execution in VM is now enabled by default (note: native code still has to be generated explicitly) * `Codegen::compile` now accepts `CodeGen_OnlyNativeModules` flag. When set, only modules that have a `--!native` hot-comment at the top will be compiled to native code In our new typechecker: * Generic type packs are no longer considered to be variadic during unification * Timeout and cancellation now works in new solver * Fixed false positive errors around 'table' and 'function' type refinements * Table literals now use covariant unification rules. This is sound since literal has no type specified and has no aliases * Fixed issues with blocked types escaping the constraint solver * Fixed more places where error messages that should've been suppressed were still reported * Fixed errors when iterating over a top table type In our native code generation (jit): * 'DebugLuauAbortingChecks' flag is now supported on A64 * LOP_NEWCLOSURE has been translated to IR
2023-07-28 08:13:53 -07:00
void* userdata;
GCObject* gclist;
int sizecode;
int sizep;
int sizelocvars;
int sizeupvalues;
int sizek;
int sizelineinfo;
int linegaplog2;
int linedefined;
int bytecodeid;
Sync to upstream/release/623 (#1236) # What's changed? ### New Type Solver - Unification of two fresh types no longer binds them together. - Replaced uses of raw `emplace` with `emplaceType` to catch cyclic bound types when they are created. - `SetIndexerConstraint` is blocked until the indexer result type is not blocked. - Fix a case where a blocked type got past the constraint solver. - Searching for free types should no longer traverse into `ClassType`s. - Fix a corner case that could result in the non-testable type `~{}`. - Fix incorrect flagging when `any` was a parameter of some checked function in nonstrict type checker. - `IterableConstraint` now consider tables without `__iter` to be iterables. ### Native Code Generation - Improve register type info lookup by program counter. - Generate type information for locals and upvalues --- ### 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: James McNellis <jmcnellis@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: 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-04-25 15:26:09 -07:00
int sizetypeinfo;
} Proto;
// clang-format on
typedef struct LocVar
{
TString* varname;
2022-08-04 15:35:33 -07:00
int startpc; // first point where variable is active
int endpc; // first point where variable is dead
uint8_t reg; // register slot, relative to base, where variable is stored
} LocVar;
/*
** Upvalues
*/
typedef struct UpVal
{
CommonHeader;
uint8_t markedopen; // set if reachable from an alive thread (only valid during atomic)
// 4 byte padding (x64)
2022-08-04 15:35:33 -07:00
TValue* v; // points to stack or to its own value
union
{
2022-08-04 15:35:33 -07:00
TValue value; // the value (when closed)
struct
{
2022-08-04 15:35:33 -07:00
// global double linked list (when open)
struct UpVal* prev;
struct UpVal* next;
// thread linked list (when open)
2022-02-24 15:53:37 -08:00
struct UpVal* threadnext;
} open;
} u;
} UpVal;
#define upisopen(up) ((up)->v != &(up)->u.value)
/*
** Closures
*/
typedef struct Closure
{
CommonHeader;
uint8_t isC;
uint8_t nupvalues;
uint8_t stacksize;
uint8_t preload;
GCObject* gclist;
struct Table* env;
union
{
struct
{
lua_CFunction f;
lua_Continuation cont;
const char* debugname;
TValue upvals[1];
} c;
struct
{
struct Proto* p;
TValue uprefs[1];
} l;
};
} Closure;
#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC)
#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->isC)
/*
** Tables
*/
typedef struct TKey
{
::Value value;
int extra[LUA_EXTRA_SIZE];
unsigned tt : 4;
2022-08-04 15:35:33 -07:00
int next : 28; // for chaining
} TKey;
typedef struct LuaNode
{
TValue val;
TKey key;
} LuaNode;
2022-08-04 15:35:33 -07:00
// copy a value into a key
#define setnodekey(L, node, obj) \
{ \
LuaNode* n_ = (node); \
const TValue* i_o = (obj); \
n_->key.value = i_o->value; \
memcpy(n_->key.extra, i_o->extra, sizeof(n_->key.extra)); \
n_->key.tt = i_o->tt; \
checkliveness(L->global, i_o); \
}
2022-08-04 15:35:33 -07:00
// copy a value from a key
#define getnodekey(L, obj, node) \
{ \
TValue* i_o = (obj); \
const LuaNode* n_ = (node); \
i_o->value = n_->key.value; \
memcpy(i_o->extra, n_->key.extra, sizeof(i_o->extra)); \
i_o->tt = n_->key.tt; \
checkliveness(L->global, i_o); \
}
// clang-format off
typedef struct Table
{
CommonHeader;
2022-08-04 15:35:33 -07:00
uint8_t tmcache; // 1<<p means tagmethod(p) is not present
uint8_t readonly; // sandboxing feature to prohibit writes to table
uint8_t safeenv; // environment doesn't share globals with other scripts
uint8_t lsizenode; // log2 of size of `node' array
uint8_t nodemask8; // (1<<lsizenode)-1, truncated to 8 bits
2022-08-04 15:35:33 -07:00
int sizearray; // size of `array' array
union
{
2022-08-04 15:35:33 -07:00
int lastfree; // any free position is before this position
int aboundary; // negated 'boundary' of `array' array; iff aboundary < 0
};
struct Table* metatable;
2022-08-04 15:35:33 -07:00
TValue* array; // array part
LuaNode* node;
GCObject* gclist;
} Table;
// clang-format on
/*
** `module' operation for hashing (size is always a power of 2)
*/
#define lmod(s, size) (check_exp((size & (size - 1)) == 0, (cast_to(int, (s) & ((size)-1)))))
#define twoto(x) ((int)(1 << (x)))
#define sizenode(t) (twoto((t)->lsizenode))
#define luaO_nilobject (&luaO_nilobject_)
LUAI_DATA const TValue luaO_nilobject_;
#define ceillog2(x) (luaO_log2((x)-1) + 1)
LUAI_FUNC int luaO_log2(unsigned int x);
LUAI_FUNC int luaO_rawequalObj(const TValue* t1, const TValue* t2);
LUAI_FUNC int luaO_rawequalKey(const TKey* t1, const TValue* t2);
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);