v0.2.2+luau521
This commit is contained in:
parent
d9a2a46c68
commit
4e923b679b
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "luau0-src"
|
name = "luau0-src"
|
||||||
version = "0.2.1+luau519"
|
version = "0.2.2+luau521"
|
||||||
authors = ["Aleksandr Orlenko <zxteam@protonmail.com>"]
|
authors = ["Aleksandr Orlenko <zxteam@protonmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/khvzak/luau-src-rs"
|
repository = "https://github.com/khvzak/luau-src-rs"
|
||||||
|
|
|
@ -130,8 +130,8 @@ ThreadContext& getThreadContext();
|
||||||
|
|
||||||
struct Scope
|
struct Scope
|
||||||
{
|
{
|
||||||
explicit Scope(ThreadContext& context, uint16_t token)
|
explicit Scope(uint16_t token)
|
||||||
: context(context)
|
: context(getThreadContext())
|
||||||
{
|
{
|
||||||
if (!FFlag::DebugLuauTimeTracing)
|
if (!FFlag::DebugLuauTimeTracing)
|
||||||
return;
|
return;
|
||||||
|
@ -152,8 +152,8 @@ struct Scope
|
||||||
|
|
||||||
struct OptionalTailScope
|
struct OptionalTailScope
|
||||||
{
|
{
|
||||||
explicit OptionalTailScope(ThreadContext& context, uint16_t token, uint32_t threshold)
|
explicit OptionalTailScope(uint16_t token, uint32_t threshold)
|
||||||
: context(context)
|
: context(getThreadContext())
|
||||||
, token(token)
|
, token(token)
|
||||||
, threshold(threshold)
|
, threshold(threshold)
|
||||||
{
|
{
|
||||||
|
@ -188,27 +188,27 @@ struct OptionalTailScope
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
LUAU_NOINLINE std::pair<uint16_t, Luau::TimeTrace::ThreadContext&> createScopeData(const char* name, const char* category);
|
LUAU_NOINLINE uint16_t createScopeData(const char* name, const char* category);
|
||||||
|
|
||||||
} // namespace TimeTrace
|
} // namespace TimeTrace
|
||||||
} // namespace Luau
|
} // namespace Luau
|
||||||
|
|
||||||
// Regular scope
|
// Regular scope
|
||||||
#define LUAU_TIMETRACE_SCOPE(name, category) \
|
#define LUAU_TIMETRACE_SCOPE(name, category) \
|
||||||
static auto lttScopeStatic = Luau::TimeTrace::createScopeData(name, category); \
|
static uint16_t lttScopeStatic = Luau::TimeTrace::createScopeData(name, category); \
|
||||||
Luau::TimeTrace::Scope lttScope(lttScopeStatic.second, lttScopeStatic.first)
|
Luau::TimeTrace::Scope lttScope(lttScopeStatic)
|
||||||
|
|
||||||
// A scope without nested scopes that may be skipped if the time it took is less than the threshold
|
// A scope without nested scopes that may be skipped if the time it took is less than the threshold
|
||||||
#define LUAU_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec) \
|
#define LUAU_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec) \
|
||||||
static auto lttScopeStaticOptTail = Luau::TimeTrace::createScopeData(name, category); \
|
static uint16_t lttScopeStaticOptTail = Luau::TimeTrace::createScopeData(name, category); \
|
||||||
Luau::TimeTrace::OptionalTailScope lttScope(lttScopeStaticOptTail.second, lttScopeStaticOptTail.first, microsec)
|
Luau::TimeTrace::OptionalTailScope lttScope(lttScopeStaticOptTail, microsec)
|
||||||
|
|
||||||
// Extra key/value data can be added to regular scopes
|
// Extra key/value data can be added to regular scopes
|
||||||
#define LUAU_TIMETRACE_ARGUMENT(name, value) \
|
#define LUAU_TIMETRACE_ARGUMENT(name, value) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
if (FFlag::DebugLuauTimeTracing) \
|
if (FFlag::DebugLuauTimeTracing) \
|
||||||
lttScopeStatic.second.eventArgument(name, value); \
|
lttScope.context.eventArgument(name, value); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauParseLocationIgnoreCommentSkip, false)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -352,6 +354,8 @@ const Lexeme& Lexer::next()
|
||||||
|
|
||||||
const Lexeme& Lexer::next(bool skipComments)
|
const Lexeme& Lexer::next(bool skipComments)
|
||||||
{
|
{
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
// in skipComments mode we reject valid comments
|
// in skipComments mode we reject valid comments
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -359,9 +363,11 @@ const Lexeme& Lexer::next(bool skipComments)
|
||||||
while (isSpace(peekch()))
|
while (isSpace(peekch()))
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
|
if (!FFlag::LuauParseLocationIgnoreCommentSkip || first)
|
||||||
prevLocation = lexeme.location;
|
prevLocation = lexeme.location;
|
||||||
|
|
||||||
lexeme = readNext();
|
lexeme = readNext();
|
||||||
|
first = false;
|
||||||
} while (skipComments && (lexeme.type == Lexeme::Comment || lexeme.type == Lexeme::BlockComment));
|
} while (skipComments && (lexeme.type == Lexeme::Comment || lexeme.type == Lexeme::BlockComment));
|
||||||
|
|
||||||
return lexeme;
|
return lexeme;
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
// See docs/SyntaxChanges.md for an explanation.
|
// See docs/SyntaxChanges.md for an explanation.
|
||||||
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
||||||
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauParseSingletonTypes, false)
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTableFieldFunctionDebugname, false)
|
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -1233,8 +1231,7 @@ AstType* Parser::parseTableTypeAnnotation()
|
||||||
|
|
||||||
while (lexer.current().type != '}')
|
while (lexer.current().type != '}')
|
||||||
{
|
{
|
||||||
if (FFlag::LuauParseSingletonTypes && lexer.current().type == '[' &&
|
if (lexer.current().type == '[' && (lexer.lookahead().type == Lexeme::RawString || lexer.lookahead().type == Lexeme::QuotedString))
|
||||||
(lexer.lookahead().type == Lexeme::RawString || lexer.lookahead().type == Lexeme::QuotedString))
|
|
||||||
{
|
{
|
||||||
const Lexeme begin = lexer.current();
|
const Lexeme begin = lexer.current();
|
||||||
nextLexeme(); // [
|
nextLexeme(); // [
|
||||||
|
@ -1500,17 +1497,17 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
return {allocator.alloc<AstTypeReference>(begin, std::nullopt, nameNil), {}};
|
return {allocator.alloc<AstTypeReference>(begin, std::nullopt, nameNil), {}};
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauParseSingletonTypes && lexer.current().type == Lexeme::ReservedTrue)
|
else if (lexer.current().type == Lexeme::ReservedTrue)
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
return {allocator.alloc<AstTypeSingletonBool>(begin, true)};
|
return {allocator.alloc<AstTypeSingletonBool>(begin, true)};
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauParseSingletonTypes && lexer.current().type == Lexeme::ReservedFalse)
|
else if (lexer.current().type == Lexeme::ReservedFalse)
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
return {allocator.alloc<AstTypeSingletonBool>(begin, false)};
|
return {allocator.alloc<AstTypeSingletonBool>(begin, false)};
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauParseSingletonTypes && (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString))
|
else if (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString)
|
||||||
{
|
{
|
||||||
if (std::optional<AstArray<char>> value = parseCharArray())
|
if (std::optional<AstArray<char>> value = parseCharArray())
|
||||||
{
|
{
|
||||||
|
@ -1520,7 +1517,7 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
|
||||||
else
|
else
|
||||||
return {reportTypeAnnotationError(begin, {}, /*isMissing*/ false, "String literal contains malformed escape sequence")};
|
return {reportTypeAnnotationError(begin, {}, /*isMissing*/ false, "String literal contains malformed escape sequence")};
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauParseSingletonTypes && lexer.current().type == Lexeme::BrokenString)
|
else if (lexer.current().type == Lexeme::BrokenString)
|
||||||
{
|
{
|
||||||
Location location = lexer.current().location;
|
Location location = lexer.current().location;
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
|
@ -2189,11 +2186,8 @@ AstExpr* Parser::parseTableConstructor()
|
||||||
AstExpr* key = allocator.alloc<AstExprConstantString>(name.location, nameString);
|
AstExpr* key = allocator.alloc<AstExprConstantString>(name.location, nameString);
|
||||||
AstExpr* value = parseExpr();
|
AstExpr* value = parseExpr();
|
||||||
|
|
||||||
if (FFlag::LuauTableFieldFunctionDebugname)
|
|
||||||
{
|
|
||||||
if (AstExprFunction* func = value->as<AstExprFunction>())
|
if (AstExprFunction* func = value->as<AstExprFunction>())
|
||||||
func->debugname = name.name;
|
func->debugname = name.name;
|
||||||
}
|
|
||||||
|
|
||||||
items.push_back({AstExprTable::Item::Record, key, value});
|
items.push_back({AstExprTable::Item::Record, key, value});
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,10 +246,9 @@ ThreadContext& getThreadContext()
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<uint16_t, Luau::TimeTrace::ThreadContext&> createScopeData(const char* name, const char* category)
|
uint16_t createScopeData(const char* name, const char* category)
|
||||||
{
|
{
|
||||||
uint16_t token = createToken(Luau::TimeTrace::getGlobalContext(), name, category);
|
return createToken(Luau::TimeTrace::getGlobalContext(), name, category);
|
||||||
return {token, Luau::TimeTrace::getThreadContext()};
|
|
||||||
}
|
}
|
||||||
} // namespace TimeTrace
|
} // namespace TimeTrace
|
||||||
} // namespace Luau
|
} // namespace Luau
|
||||||
|
|
|
@ -376,8 +376,7 @@ enum LuauOpcode
|
||||||
enum LuauBytecodeTag
|
enum LuauBytecodeTag
|
||||||
{
|
{
|
||||||
// Bytecode version
|
// Bytecode version
|
||||||
LBC_VERSION = 1,
|
LBC_VERSION = 2,
|
||||||
LBC_VERSION_FUTURE = 2, // TODO: This will be removed in favor of LBC_VERSION with LuauBytecodeV2Force
|
|
||||||
// Types of constant table entries
|
// Types of constant table entries
|
||||||
LBC_CONSTANT_NIL = 0,
|
LBC_CONSTANT_NIL = 0,
|
||||||
LBC_CONSTANT_BOOLEAN,
|
LBC_CONSTANT_BOOLEAN,
|
||||||
|
|
|
@ -508,7 +508,7 @@ uint32_t BytecodeBuilder::getDebugPC() const
|
||||||
void BytecodeBuilder::finalize()
|
void BytecodeBuilder::finalize()
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(bytecode.empty());
|
LUAU_ASSERT(bytecode.empty());
|
||||||
bytecode = char(LBC_VERSION_FUTURE);
|
bytecode = char(LBC_VERSION);
|
||||||
|
|
||||||
writeStringTable(bytecode);
|
writeStringTable(bytecode);
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauGcAdditionalStats)
|
|
||||||
|
|
||||||
const char* lua_ident = "$Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio $\n"
|
const char* lua_ident = "$Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio $\n"
|
||||||
"$Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes $\n"
|
"$Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes $\n"
|
||||||
"$URL: www.lua.org $\n";
|
"$URL: www.lua.org $\n";
|
||||||
|
@ -1060,8 +1058,11 @@ int lua_gc(lua_State* L, int what, int data)
|
||||||
g->GCthreshold = 0;
|
g->GCthreshold = 0;
|
||||||
|
|
||||||
bool waspaused = g->gcstate == GCSpause;
|
bool waspaused = g->gcstate == GCSpause;
|
||||||
double startmarktime = g->gcstats.currcycle.marktime;
|
|
||||||
double startsweeptime = g->gcstats.currcycle.sweeptime;
|
#ifdef LUAI_GCMETRICS
|
||||||
|
double startmarktime = g->gcmetrics.currcycle.marktime;
|
||||||
|
double startsweeptime = g->gcmetrics.currcycle.sweeptime;
|
||||||
|
#endif
|
||||||
|
|
||||||
// track how much work the loop will actually perform
|
// track how much work the loop will actually perform
|
||||||
size_t actualwork = 0;
|
size_t actualwork = 0;
|
||||||
|
@ -1079,30 +1080,29 @@ int lua_gc(lua_State* L, int what, int data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
{
|
|
||||||
// record explicit step statistics
|
// record explicit step statistics
|
||||||
GCCycleStats* cyclestats = g->gcstate == GCSpause ? &g->gcstats.lastcycle : &g->gcstats.currcycle;
|
GCCycleMetrics* cyclemetrics = g->gcstate == GCSpause ? &g->gcmetrics.lastcycle : &g->gcmetrics.currcycle;
|
||||||
|
|
||||||
double totalmarktime = cyclestats->marktime - startmarktime;
|
double totalmarktime = cyclemetrics->marktime - startmarktime;
|
||||||
double totalsweeptime = cyclestats->sweeptime - startsweeptime;
|
double totalsweeptime = cyclemetrics->sweeptime - startsweeptime;
|
||||||
|
|
||||||
if (totalmarktime > 0.0)
|
if (totalmarktime > 0.0)
|
||||||
{
|
{
|
||||||
cyclestats->markexplicitsteps++;
|
cyclemetrics->markexplicitsteps++;
|
||||||
|
|
||||||
if (totalmarktime > cyclestats->markmaxexplicittime)
|
if (totalmarktime > cyclemetrics->markmaxexplicittime)
|
||||||
cyclestats->markmaxexplicittime = totalmarktime;
|
cyclemetrics->markmaxexplicittime = totalmarktime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalsweeptime > 0.0)
|
if (totalsweeptime > 0.0)
|
||||||
{
|
{
|
||||||
cyclestats->sweepexplicitsteps++;
|
cyclemetrics->sweepexplicitsteps++;
|
||||||
|
|
||||||
if (totalsweeptime > cyclestats->sweepmaxexplicittime)
|
if (totalsweeptime > cyclemetrics->sweepmaxexplicittime)
|
||||||
cyclestats->sweepmaxexplicittime = totalsweeptime;
|
cyclemetrics->sweepmaxexplicittime = totalsweeptime;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// if cycle hasn't finished, advance threshold forward for the amount of extra work performed
|
// if cycle hasn't finished, advance threshold forward for the amount of extra work performed
|
||||||
if (g->gcstate != GCSpause)
|
if (g->gcstate != GCSpause)
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauMorePreciseLuaLTypeName, false)
|
|
||||||
|
|
||||||
/* convert a stack index to positive */
|
/* convert a stack index to positive */
|
||||||
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
|
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
|
||||||
|
|
||||||
|
@ -337,15 +335,8 @@ const char* luaL_findtable(lua_State* L, int idx, const char* fname, int szhint)
|
||||||
|
|
||||||
const char* luaL_typename(lua_State* L, int idx)
|
const char* luaL_typename(lua_State* L, int idx)
|
||||||
{
|
{
|
||||||
if (DFFlag::LuauMorePreciseLuaLTypeName)
|
|
||||||
{
|
|
||||||
const TValue* obj = luaA_toobject(L, idx);
|
const TValue* obj = luaA_toobject(L, idx);
|
||||||
return luaT_objtypename(L, obj);
|
return luaT_objtypename(L, obj);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return lua_typename(L, lua_type(L, idx));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
LUAU_DYNAMIC_FASTFLAG(LuauMorePreciseLuaLTypeName)
|
|
||||||
|
|
||||||
static void writestring(const char* s, size_t l)
|
static void writestring(const char* s, size_t l)
|
||||||
{
|
{
|
||||||
fwrite(s, 1, l, stdout);
|
fwrite(s, 1, l, stdout);
|
||||||
|
@ -189,31 +187,16 @@ static int luaB_gcinfo(lua_State* L)
|
||||||
static int luaB_type(lua_State* L)
|
static int luaB_type(lua_State* L)
|
||||||
{
|
{
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
if (DFFlag::LuauMorePreciseLuaLTypeName)
|
|
||||||
{
|
|
||||||
/* resulting name doesn't differentiate between userdata types */
|
/* resulting name doesn't differentiate between userdata types */
|
||||||
lua_pushstring(L, lua_typename(L, lua_type(L, 1)));
|
lua_pushstring(L, lua_typename(L, lua_type(L, 1)));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lua_pushstring(L, luaL_typename(L, 1));
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int luaB_typeof(lua_State* L)
|
static int luaB_typeof(lua_State* L)
|
||||||
{
|
{
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
if (DFFlag::LuauMorePreciseLuaLTypeName)
|
|
||||||
{
|
|
||||||
/* resulting name returns __type if specified unless the input is a newproxy-created userdata */
|
/* resulting name returns __type if specified unless the input is a newproxy-created userdata */
|
||||||
lua_pushstring(L, luaL_typename(L, 1));
|
lua_pushstring(L, luaL_typename(L, 1));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const TValue* obj = luaA_toobject(L, 1);
|
|
||||||
lua_pushstring(L, luaT_objtypename(L, obj));
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauBytecodeV2Force)
|
|
||||||
|
|
||||||
static const char* getfuncname(Closure* f);
|
static const char* getfuncname(Closure* f);
|
||||||
|
|
||||||
static int currentpc(lua_State* L, CallInfo* ci)
|
static int currentpc(lua_State* L, CallInfo* ci)
|
||||||
|
@ -91,16 +89,6 @@ const char* lua_setlocal(lua_State* L, int level, int n)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getlinedefined(Proto* p)
|
|
||||||
{
|
|
||||||
if (FFlag::LuauBytecodeV2Force)
|
|
||||||
return p->linedefined;
|
|
||||||
else if (p->linedefined >= 0)
|
|
||||||
return p->linedefined;
|
|
||||||
else
|
|
||||||
return luaG_getline(p, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int auxgetinfo(lua_State* L, const char* what, lua_Debug* ar, Closure* f, CallInfo* ci)
|
static int auxgetinfo(lua_State* L, const char* what, lua_Debug* ar, Closure* f, CallInfo* ci)
|
||||||
{
|
{
|
||||||
int status = 1;
|
int status = 1;
|
||||||
|
@ -120,7 +108,7 @@ static int auxgetinfo(lua_State* L, const char* what, lua_Debug* ar, Closure* f,
|
||||||
{
|
{
|
||||||
ar->source = getstr(f->l.p->source);
|
ar->source = getstr(f->l.p->source);
|
||||||
ar->what = "Lua";
|
ar->what = "Lua";
|
||||||
ar->linedefined = getlinedefined(f->l.p);
|
ar->linedefined = f->l.p->linedefined;
|
||||||
}
|
}
|
||||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||||
break;
|
break;
|
||||||
|
@ -133,7 +121,7 @@ static int auxgetinfo(lua_State* L, const char* what, lua_Debug* ar, Closure* f,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ar->currentline = f->isC ? -1 : getlinedefined(f->l.p);
|
ar->currentline = f->isC ? -1 : f->l.p->linedefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -424,7 +412,7 @@ static void getcoverage(Proto* p, int depth, int* buffer, size_t size, void* con
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* debugname = p->debugname ? getstr(p->debugname) : NULL;
|
const char* debugname = p->debugname ? getstr(p->debugname) : NULL;
|
||||||
int linedefined = getlinedefined(p);
|
int linedefined = p->linedefined;
|
||||||
|
|
||||||
callback(context, debugname, linedefined, depth, buffer, size);
|
callback(context, debugname, linedefined, depth, buffer, size);
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauReduceStackReallocs)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================
|
** {======================================================
|
||||||
** Error-recovery functions
|
** Error-recovery functions
|
||||||
|
@ -33,6 +31,15 @@ struct lua_jmpbuf
|
||||||
jmp_buf buf;
|
jmp_buf buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* use POSIX versions of setjmp/longjmp if possible: they don't save/restore signal mask and are therefore faster */
|
||||||
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
|
#define LUAU_SETJMP(buf) _setjmp(buf)
|
||||||
|
#define LUAU_LONGJMP(buf, code) _longjmp(buf, code)
|
||||||
|
#else
|
||||||
|
#define LUAU_SETJMP(buf) setjmp(buf)
|
||||||
|
#define LUAU_LONGJMP(buf, code) longjmp(buf, code)
|
||||||
|
#endif
|
||||||
|
|
||||||
int luaD_rawrunprotected(lua_State* L, Pfunc f, void* ud)
|
int luaD_rawrunprotected(lua_State* L, Pfunc f, void* ud)
|
||||||
{
|
{
|
||||||
lua_jmpbuf jb;
|
lua_jmpbuf jb;
|
||||||
|
@ -40,7 +47,7 @@ int luaD_rawrunprotected(lua_State* L, Pfunc f, void* ud)
|
||||||
jb.status = 0;
|
jb.status = 0;
|
||||||
L->global->errorjmp = &jb;
|
L->global->errorjmp = &jb;
|
||||||
|
|
||||||
if (setjmp(jb.buf) == 0)
|
if (LUAU_SETJMP(jb.buf) == 0)
|
||||||
f(L, ud);
|
f(L, ud);
|
||||||
|
|
||||||
L->global->errorjmp = jb.prev;
|
L->global->errorjmp = jb.prev;
|
||||||
|
@ -52,7 +59,7 @@ l_noret luaD_throw(lua_State* L, int errcode)
|
||||||
if (lua_jmpbuf* jb = L->global->errorjmp)
|
if (lua_jmpbuf* jb = L->global->errorjmp)
|
||||||
{
|
{
|
||||||
jb->status = errcode;
|
jb->status = errcode;
|
||||||
longjmp(jb->buf, 1);
|
LUAU_LONGJMP(jb->buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (L->global->cb.panic)
|
if (L->global->cb.panic)
|
||||||
|
@ -165,8 +172,8 @@ static void correctstack(lua_State* L, TValue* oldstack)
|
||||||
void luaD_reallocstack(lua_State* L, int newsize)
|
void luaD_reallocstack(lua_State* L, int newsize)
|
||||||
{
|
{
|
||||||
TValue* oldstack = L->stack;
|
TValue* oldstack = L->stack;
|
||||||
int realsize = newsize + (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK);
|
int realsize = newsize + EXTRA_STACK;
|
||||||
LUAU_ASSERT(L->stack_last - L->stack == L->stacksize - (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK));
|
LUAU_ASSERT(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
|
||||||
luaM_reallocarray(L, L->stack, L->stacksize, realsize, TValue, L->memcat);
|
luaM_reallocarray(L, L->stack, L->stacksize, realsize, TValue, L->memcat);
|
||||||
TValue* newstack = L->stack;
|
TValue* newstack = L->stack;
|
||||||
for (int i = L->stacksize; i < realsize; i++)
|
for (int i = L->stacksize; i < realsize; i++)
|
||||||
|
@ -514,7 +521,7 @@ static void callerrfunc(lua_State* L, void* ud)
|
||||||
|
|
||||||
static void restore_stack_limit(lua_State* L)
|
static void restore_stack_limit(lua_State* L)
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(L->stack_last - L->stack == L->stacksize - (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK));
|
LUAU_ASSERT(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
|
||||||
if (L->size_ci > LUAI_MAXCALLS)
|
if (L->size_ci > LUAI_MAXCALLS)
|
||||||
{ /* there was an overflow? */
|
{ /* there was an overflow? */
|
||||||
int inuse = cast_int(L->ci - L->base_ci);
|
int inuse = cast_int(L->ci - L->base_ci);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
if ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue)) \
|
if ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue)) \
|
||||||
luaD_growstack(L, n); \
|
luaD_growstack(L, n); \
|
||||||
else \
|
else \
|
||||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK)));
|
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK));
|
||||||
|
|
||||||
#define incr_top(L) \
|
#define incr_top(L) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "ludata.h"
|
#include "ludata.h"
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauGcAdditionalStats, false)
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define GC_SWEEPMAX 40
|
#define GC_SWEEPMAX 40
|
||||||
|
@ -48,7 +46,8 @@ LUAU_FASTFLAGVARIABLE(LuauGcAdditionalStats, false)
|
||||||
reallymarkobject(g, obj2gco(t)); \
|
reallymarkobject(g, obj2gco(t)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recordGcStateTime(global_State* g, int startgcstate, double seconds, bool assist)
|
#ifdef LUAI_GCMETRICS
|
||||||
|
static void recordGcStateStep(global_State* g, int startgcstate, double seconds, bool assist, size_t work)
|
||||||
{
|
{
|
||||||
switch (startgcstate)
|
switch (startgcstate)
|
||||||
{
|
{
|
||||||
|
@ -56,58 +55,76 @@ static void recordGcStateTime(global_State* g, int startgcstate, double seconds,
|
||||||
// record root mark time if we have switched to next state
|
// record root mark time if we have switched to next state
|
||||||
if (g->gcstate == GCSpropagate)
|
if (g->gcstate == GCSpropagate)
|
||||||
{
|
{
|
||||||
g->gcstats.currcycle.marktime += seconds;
|
g->gcmetrics.currcycle.marktime += seconds;
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats && assist)
|
if (assist)
|
||||||
g->gcstats.currcycle.markassisttime += seconds;
|
g->gcmetrics.currcycle.markassisttime += seconds;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GCSpropagate:
|
case GCSpropagate:
|
||||||
case GCSpropagateagain:
|
case GCSpropagateagain:
|
||||||
g->gcstats.currcycle.marktime += seconds;
|
g->gcmetrics.currcycle.marktime += seconds;
|
||||||
|
g->gcmetrics.currcycle.markrequests += g->gcstepsize;
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats && assist)
|
if (assist)
|
||||||
g->gcstats.currcycle.markassisttime += seconds;
|
g->gcmetrics.currcycle.markassisttime += seconds;
|
||||||
break;
|
break;
|
||||||
case GCSatomic:
|
case GCSatomic:
|
||||||
g->gcstats.currcycle.atomictime += seconds;
|
g->gcmetrics.currcycle.atomictime += seconds;
|
||||||
break;
|
break;
|
||||||
case GCSsweep:
|
case GCSsweep:
|
||||||
g->gcstats.currcycle.sweeptime += seconds;
|
g->gcmetrics.currcycle.sweeptime += seconds;
|
||||||
|
g->gcmetrics.currcycle.sweeprequests += g->gcstepsize;
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats && assist)
|
if (assist)
|
||||||
g->gcstats.currcycle.sweepassisttime += seconds;
|
g->gcmetrics.currcycle.sweepassisttime += seconds;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LUAU_ASSERT(!"Unexpected GC state");
|
LUAU_ASSERT(!"Unexpected GC state");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assist)
|
if (assist)
|
||||||
g->gcstats.stepassisttimeacc += seconds;
|
{
|
||||||
|
g->gcmetrics.stepassisttimeacc += seconds;
|
||||||
|
g->gcmetrics.currcycle.assistwork += work;
|
||||||
|
g->gcmetrics.currcycle.assistrequests += g->gcstepsize;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
g->gcstats.stepexplicittimeacc += seconds;
|
{
|
||||||
|
g->gcmetrics.stepexplicittimeacc += seconds;
|
||||||
|
g->gcmetrics.currcycle.explicitwork += work;
|
||||||
|
g->gcmetrics.currcycle.explicitrequests += g->gcstepsize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void startGcCycleStats(global_State* g)
|
static double recordGcDeltaTime(double& timer)
|
||||||
{
|
{
|
||||||
g->gcstats.currcycle.starttimestamp = lua_clock();
|
double now = lua_clock();
|
||||||
g->gcstats.currcycle.pausetime = g->gcstats.currcycle.starttimestamp - g->gcstats.lastcycle.endtimestamp;
|
double delta = now - timer;
|
||||||
|
timer = now;
|
||||||
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finishGcCycleStats(global_State* g)
|
static void startGcCycleMetrics(global_State* g)
|
||||||
{
|
{
|
||||||
g->gcstats.currcycle.endtimestamp = lua_clock();
|
g->gcmetrics.currcycle.starttimestamp = lua_clock();
|
||||||
g->gcstats.currcycle.endtotalsizebytes = g->totalbytes;
|
g->gcmetrics.currcycle.pausetime = g->gcmetrics.currcycle.starttimestamp - g->gcmetrics.lastcycle.endtimestamp;
|
||||||
|
|
||||||
g->gcstats.completedcycles++;
|
|
||||||
g->gcstats.lastcycle = g->gcstats.currcycle;
|
|
||||||
g->gcstats.currcycle = GCCycleStats();
|
|
||||||
|
|
||||||
g->gcstats.cyclestatsacc.marktime += g->gcstats.lastcycle.marktime;
|
|
||||||
g->gcstats.cyclestatsacc.atomictime += g->gcstats.lastcycle.atomictime;
|
|
||||||
g->gcstats.cyclestatsacc.sweeptime += g->gcstats.lastcycle.sweeptime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void finishGcCycleMetrics(global_State* g)
|
||||||
|
{
|
||||||
|
g->gcmetrics.currcycle.endtimestamp = lua_clock();
|
||||||
|
g->gcmetrics.currcycle.endtotalsizebytes = g->totalbytes;
|
||||||
|
|
||||||
|
g->gcmetrics.completedcycles++;
|
||||||
|
g->gcmetrics.lastcycle = g->gcmetrics.currcycle;
|
||||||
|
g->gcmetrics.currcycle = GCCycleMetrics();
|
||||||
|
|
||||||
|
g->gcmetrics.currcycle.starttotalsizebytes = g->totalbytes;
|
||||||
|
g->gcmetrics.currcycle.heaptriggersizebytes = g->GCthreshold;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void removeentry(LuaNode* n)
|
static void removeentry(LuaNode* n)
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(ttisnil(gval(n)));
|
LUAU_ASSERT(ttisnil(gval(n)));
|
||||||
|
@ -598,20 +615,19 @@ static size_t atomic(lua_State* L)
|
||||||
LUAU_ASSERT(g->gcstate == GCSatomic);
|
LUAU_ASSERT(g->gcstate == GCSatomic);
|
||||||
|
|
||||||
size_t work = 0;
|
size_t work = 0;
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
double currts = lua_clock();
|
double currts = lua_clock();
|
||||||
double prevts = currts;
|
#endif
|
||||||
|
|
||||||
/* remark occasional upvalues of (maybe) dead threads */
|
/* remark occasional upvalues of (maybe) dead threads */
|
||||||
work += remarkupvals(g);
|
work += remarkupvals(g);
|
||||||
/* traverse objects caught by write barrier and by 'remarkupvals' */
|
/* traverse objects caught by write barrier and by 'remarkupvals' */
|
||||||
work += propagateall(g);
|
work += propagateall(g);
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
{
|
g->gcmetrics.currcycle.atomictimeupval += recordGcDeltaTime(currts);
|
||||||
currts = lua_clock();
|
#endif
|
||||||
g->gcstats.currcycle.atomictimeupval += currts - prevts;
|
|
||||||
prevts = currts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remark weak tables */
|
/* remark weak tables */
|
||||||
g->gray = g->weak;
|
g->gray = g->weak;
|
||||||
|
@ -621,34 +637,26 @@ static size_t atomic(lua_State* L)
|
||||||
markmt(g); /* mark basic metatables (again) */
|
markmt(g); /* mark basic metatables (again) */
|
||||||
work += propagateall(g);
|
work += propagateall(g);
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
{
|
g->gcmetrics.currcycle.atomictimeweak += recordGcDeltaTime(currts);
|
||||||
currts = lua_clock();
|
#endif
|
||||||
g->gcstats.currcycle.atomictimeweak += currts - prevts;
|
|
||||||
prevts = currts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remark gray again */
|
/* remark gray again */
|
||||||
g->gray = g->grayagain;
|
g->gray = g->grayagain;
|
||||||
g->grayagain = NULL;
|
g->grayagain = NULL;
|
||||||
work += propagateall(g);
|
work += propagateall(g);
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
{
|
g->gcmetrics.currcycle.atomictimegray += recordGcDeltaTime(currts);
|
||||||
currts = lua_clock();
|
#endif
|
||||||
g->gcstats.currcycle.atomictimegray += currts - prevts;
|
|
||||||
prevts = currts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove collected objects from weak tables */
|
/* remove collected objects from weak tables */
|
||||||
work += cleartable(L, g->weak);
|
work += cleartable(L, g->weak);
|
||||||
g->weak = NULL;
|
g->weak = NULL;
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
{
|
g->gcmetrics.currcycle.atomictimeclear += recordGcDeltaTime(currts);
|
||||||
currts = lua_clock();
|
#endif
|
||||||
g->gcstats.currcycle.atomictimeclear += currts - prevts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flip current white */
|
/* flip current white */
|
||||||
g->currentwhite = cast_byte(otherwhite(g));
|
g->currentwhite = cast_byte(otherwhite(g));
|
||||||
|
@ -742,8 +750,9 @@ static size_t gcstep(lua_State* L, size_t limit)
|
||||||
|
|
||||||
if (!g->gray)
|
if (!g->gray)
|
||||||
{
|
{
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.propagatework = g->gcstats.currcycle.explicitwork + g->gcstats.currcycle.assistwork;
|
g->gcmetrics.currcycle.propagatework = g->gcmetrics.currcycle.explicitwork + g->gcmetrics.currcycle.assistwork;
|
||||||
|
#endif
|
||||||
|
|
||||||
// perform one iteration over 'gray again' list
|
// perform one iteration over 'gray again' list
|
||||||
g->gray = g->grayagain;
|
g->gray = g->grayagain;
|
||||||
|
@ -762,9 +771,10 @@ static size_t gcstep(lua_State* L, size_t limit)
|
||||||
|
|
||||||
if (!g->gray) /* no more `gray' objects */
|
if (!g->gray) /* no more `gray' objects */
|
||||||
{
|
{
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.propagateagainwork =
|
g->gcmetrics.currcycle.propagateagainwork =
|
||||||
g->gcstats.currcycle.explicitwork + g->gcstats.currcycle.assistwork - g->gcstats.currcycle.propagatework;
|
g->gcmetrics.currcycle.explicitwork + g->gcmetrics.currcycle.assistwork - g->gcmetrics.currcycle.propagatework;
|
||||||
|
#endif
|
||||||
|
|
||||||
g->gcstate = GCSatomic;
|
g->gcstate = GCSatomic;
|
||||||
}
|
}
|
||||||
|
@ -772,8 +782,13 @@ static size_t gcstep(lua_State* L, size_t limit)
|
||||||
}
|
}
|
||||||
case GCSatomic:
|
case GCSatomic:
|
||||||
{
|
{
|
||||||
g->gcstats.currcycle.atomicstarttimestamp = lua_clock();
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.atomicstarttotalsizebytes = g->totalbytes;
|
g->gcmetrics.currcycle.atomicstarttimestamp = lua_clock();
|
||||||
|
g->gcmetrics.currcycle.atomicstarttotalsizebytes = g->totalbytes;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g->gcstats.atomicstarttimestamp = lua_clock();
|
||||||
|
g->gcstats.atomicstarttotalsizebytes = g->totalbytes;
|
||||||
|
|
||||||
cost = atomic(L); /* finish mark phase */
|
cost = atomic(L); /* finish mark phase */
|
||||||
|
|
||||||
|
@ -809,18 +824,20 @@ static size_t gcstep(lua_State* L, size_t limit)
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t getheaptriggererroroffset(GCHeapTriggerStats* triggerstats, GCCycleStats* cyclestats)
|
static int64_t getheaptriggererroroffset(global_State* g)
|
||||||
{
|
{
|
||||||
// adjust for error using Proportional-Integral controller
|
// adjust for error using Proportional-Integral controller
|
||||||
// https://en.wikipedia.org/wiki/PID_controller
|
// https://en.wikipedia.org/wiki/PID_controller
|
||||||
int32_t errorKb = int32_t((cyclestats->atomicstarttotalsizebytes - cyclestats->heapgoalsizebytes) / 1024);
|
int32_t errorKb = int32_t((g->gcstats.atomicstarttotalsizebytes - g->gcstats.heapgoalsizebytes) / 1024);
|
||||||
|
|
||||||
// we use sliding window for the error integral to avoid error sum 'windup' when the desired target cannot be reached
|
// we use sliding window for the error integral to avoid error sum 'windup' when the desired target cannot be reached
|
||||||
int32_t* slot = &triggerstats->terms[triggerstats->termpos % triggerstats->termcount];
|
const size_t triggertermcount = sizeof(g->gcstats.triggerterms) / sizeof(g->gcstats.triggerterms[0]);
|
||||||
|
|
||||||
|
int32_t* slot = &g->gcstats.triggerterms[g->gcstats.triggertermpos % triggertermcount];
|
||||||
int32_t prev = *slot;
|
int32_t prev = *slot;
|
||||||
*slot = errorKb;
|
*slot = errorKb;
|
||||||
triggerstats->integral += errorKb - prev;
|
g->gcstats.triggerintegral += errorKb - prev;
|
||||||
triggerstats->termpos++;
|
g->gcstats.triggertermpos++;
|
||||||
|
|
||||||
// controller tuning
|
// controller tuning
|
||||||
// https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
|
// https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
|
||||||
|
@ -832,7 +849,7 @@ static int64_t getheaptriggererroroffset(GCHeapTriggerStats* triggerstats, GCCyc
|
||||||
const double Ki = 0.54 * Ku / Ti; // integral gain
|
const double Ki = 0.54 * Ku / Ti; // integral gain
|
||||||
|
|
||||||
double proportionalTerm = Kp * errorKb;
|
double proportionalTerm = Kp * errorKb;
|
||||||
double integralTerm = Ki * triggerstats->integral;
|
double integralTerm = Ki * g->gcstats.triggerintegral;
|
||||||
|
|
||||||
double totalTerm = proportionalTerm + integralTerm;
|
double totalTerm = proportionalTerm + integralTerm;
|
||||||
|
|
||||||
|
@ -841,23 +858,20 @@ static int64_t getheaptriggererroroffset(GCHeapTriggerStats* triggerstats, GCCyc
|
||||||
|
|
||||||
static size_t getheaptrigger(global_State* g, size_t heapgoal)
|
static size_t getheaptrigger(global_State* g, size_t heapgoal)
|
||||||
{
|
{
|
||||||
GCCycleStats* lastcycle = &g->gcstats.lastcycle;
|
|
||||||
GCCycleStats* currcycle = &g->gcstats.currcycle;
|
|
||||||
|
|
||||||
// adjust threshold based on a guess of how many bytes will be allocated between the cycle start and sweep phase
|
// adjust threshold based on a guess of how many bytes will be allocated between the cycle start and sweep phase
|
||||||
// our goal is to begin the sweep when used memory has reached the heap goal
|
// our goal is to begin the sweep when used memory has reached the heap goal
|
||||||
const double durationthreshold = 1e-3;
|
const double durationthreshold = 1e-3;
|
||||||
double allocationduration = currcycle->atomicstarttimestamp - lastcycle->endtimestamp;
|
double allocationduration = g->gcstats.atomicstarttimestamp - g->gcstats.endtimestamp;
|
||||||
|
|
||||||
// avoid measuring intervals smaller than 1ms
|
// avoid measuring intervals smaller than 1ms
|
||||||
if (allocationduration < durationthreshold)
|
if (allocationduration < durationthreshold)
|
||||||
return heapgoal;
|
return heapgoal;
|
||||||
|
|
||||||
double allocationrate = (currcycle->atomicstarttotalsizebytes - lastcycle->endtotalsizebytes) / allocationduration;
|
double allocationrate = (g->gcstats.atomicstarttotalsizebytes - g->gcstats.endtotalsizebytes) / allocationduration;
|
||||||
double markduration = currcycle->atomicstarttimestamp - currcycle->starttimestamp;
|
double markduration = g->gcstats.atomicstarttimestamp - g->gcstats.starttimestamp;
|
||||||
|
|
||||||
int64_t expectedgrowth = int64_t(markduration * allocationrate);
|
int64_t expectedgrowth = int64_t(markduration * allocationrate);
|
||||||
int64_t offset = getheaptriggererroroffset(&g->gcstats.triggerstats, currcycle);
|
int64_t offset = getheaptriggererroroffset(g);
|
||||||
int64_t heaptrigger = heapgoal - (expectedgrowth + offset);
|
int64_t heaptrigger = heapgoal - (expectedgrowth + offset);
|
||||||
|
|
||||||
// clamp the trigger between memory use at the end of the cycle and the heap goal
|
// clamp the trigger between memory use at the end of the cycle and the heap goal
|
||||||
|
@ -868,11 +882,6 @@ void luaC_step(lua_State* L, bool assist)
|
||||||
{
|
{
|
||||||
global_State* g = L->global;
|
global_State* g = L->global;
|
||||||
|
|
||||||
if (assist)
|
|
||||||
g->gcstats.currcycle.assistrequests += g->gcstepsize;
|
|
||||||
else
|
|
||||||
g->gcstats.currcycle.explicitrequests += g->gcstepsize;
|
|
||||||
|
|
||||||
int lim = (g->gcstepsize / 100) * g->gcstepmul; /* how much to work */
|
int lim = (g->gcstepsize / 100) * g->gcstepmul; /* how much to work */
|
||||||
LUAU_ASSERT(g->totalbytes >= g->GCthreshold);
|
LUAU_ASSERT(g->totalbytes >= g->GCthreshold);
|
||||||
size_t debt = g->totalbytes - g->GCthreshold;
|
size_t debt = g->totalbytes - g->GCthreshold;
|
||||||
|
@ -881,24 +890,23 @@ void luaC_step(lua_State* L, bool assist)
|
||||||
|
|
||||||
// at the start of the new cycle
|
// at the start of the new cycle
|
||||||
if (g->gcstate == GCSpause)
|
if (g->gcstate == GCSpause)
|
||||||
startGcCycleStats(g);
|
g->gcstats.starttimestamp = lua_clock();
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
|
if (g->gcstate == GCSpause)
|
||||||
|
startGcCycleMetrics(g);
|
||||||
|
|
||||||
|
double lasttimestamp = lua_clock();
|
||||||
|
#endif
|
||||||
|
|
||||||
int lastgcstate = g->gcstate;
|
int lastgcstate = g->gcstate;
|
||||||
double lasttimestamp = lua_clock();
|
|
||||||
|
|
||||||
size_t work = gcstep(L, lim);
|
size_t work = gcstep(L, lim);
|
||||||
|
(void)work;
|
||||||
|
|
||||||
if (assist)
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.assistwork += work;
|
recordGcStateStep(g, lastgcstate, lua_clock() - lasttimestamp, assist, work);
|
||||||
else
|
#endif
|
||||||
g->gcstats.currcycle.explicitwork += work;
|
|
||||||
|
|
||||||
recordGcStateTime(g, lastgcstate, lua_clock() - lasttimestamp, assist);
|
|
||||||
|
|
||||||
if (lastgcstate == GCSpropagate)
|
|
||||||
g->gcstats.currcycle.markrequests += g->gcstepsize;
|
|
||||||
else if (lastgcstate == GCSsweep)
|
|
||||||
g->gcstats.currcycle.sweeprequests += g->gcstepsize;
|
|
||||||
|
|
||||||
// at the end of the last cycle
|
// at the end of the last cycle
|
||||||
if (g->gcstate == GCSpause)
|
if (g->gcstate == GCSpause)
|
||||||
|
@ -909,13 +917,13 @@ void luaC_step(lua_State* L, bool assist)
|
||||||
|
|
||||||
g->GCthreshold = heaptrigger;
|
g->GCthreshold = heaptrigger;
|
||||||
|
|
||||||
finishGcCycleStats(g);
|
g->gcstats.heapgoalsizebytes = heapgoal;
|
||||||
|
g->gcstats.endtimestamp = lua_clock();
|
||||||
|
g->gcstats.endtotalsizebytes = g->totalbytes;
|
||||||
|
|
||||||
if (FFlag::LuauGcAdditionalStats)
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.starttotalsizebytes = g->totalbytes;
|
finishGcCycleMetrics(g);
|
||||||
|
#endif
|
||||||
g->gcstats.currcycle.heapgoalsizebytes = heapgoal;
|
|
||||||
g->gcstats.currcycle.heaptriggersizebytes = heaptrigger;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -933,8 +941,10 @@ void luaC_fullgc(lua_State* L)
|
||||||
{
|
{
|
||||||
global_State* g = L->global;
|
global_State* g = L->global;
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
if (g->gcstate == GCSpause)
|
if (g->gcstate == GCSpause)
|
||||||
startGcCycleStats(g);
|
startGcCycleMetrics(g);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (g->gcstate <= GCSatomic)
|
if (g->gcstate <= GCSatomic)
|
||||||
{
|
{
|
||||||
|
@ -954,11 +964,12 @@ void luaC_fullgc(lua_State* L)
|
||||||
gcstep(L, SIZE_MAX);
|
gcstep(L, SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
finishGcCycleStats(g);
|
#ifdef LUAI_GCMETRICS
|
||||||
|
finishGcCycleMetrics(g);
|
||||||
|
startGcCycleMetrics(g);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* run a full collection cycle */
|
/* run a full collection cycle */
|
||||||
startGcCycleStats(g);
|
|
||||||
|
|
||||||
markroot(L);
|
markroot(L);
|
||||||
while (g->gcstate != GCSpause)
|
while (g->gcstate != GCSpause)
|
||||||
{
|
{
|
||||||
|
@ -980,10 +991,11 @@ void luaC_fullgc(lua_State* L)
|
||||||
if (g->GCthreshold < g->totalbytes)
|
if (g->GCthreshold < g->totalbytes)
|
||||||
g->GCthreshold = g->totalbytes;
|
g->GCthreshold = g->totalbytes;
|
||||||
|
|
||||||
finishGcCycleStats(g);
|
g->gcstats.heapgoalsizebytes = heapgoalsizebytes;
|
||||||
|
|
||||||
g->gcstats.currcycle.heapgoalsizebytes = heapgoalsizebytes;
|
#ifdef LUAI_GCMETRICS
|
||||||
g->gcstats.currcycle.heaptriggersizebytes = g->GCthreshold;
|
finishGcCycleMetrics(g);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void luaC_barrierupval(lua_State* L, GCObject* v)
|
void luaC_barrierupval(lua_State* L, GCObject* v)
|
||||||
|
@ -1075,21 +1087,21 @@ int64_t luaC_allocationrate(lua_State* L)
|
||||||
|
|
||||||
if (g->gcstate <= GCSatomic)
|
if (g->gcstate <= GCSatomic)
|
||||||
{
|
{
|
||||||
double duration = lua_clock() - g->gcstats.lastcycle.endtimestamp;
|
double duration = lua_clock() - g->gcstats.endtimestamp;
|
||||||
|
|
||||||
if (duration < durationthreshold)
|
if (duration < durationthreshold)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return int64_t((g->totalbytes - g->gcstats.lastcycle.endtotalsizebytes) / duration);
|
return int64_t((g->totalbytes - g->gcstats.endtotalsizebytes) / duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// totalbytes is unstable during the sweep, use the rate measured at the end of mark phase
|
// totalbytes is unstable during the sweep, use the rate measured at the end of mark phase
|
||||||
double duration = g->gcstats.currcycle.atomicstarttimestamp - g->gcstats.lastcycle.endtimestamp;
|
double duration = g->gcstats.atomicstarttimestamp - g->gcstats.endtimestamp;
|
||||||
|
|
||||||
if (duration < durationthreshold)
|
if (duration < durationthreshold)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return int64_t((g->gcstats.currcycle.atomicstarttotalsizebytes - g->gcstats.lastcycle.endtotalsizebytes) / duration);
|
return int64_t((g->gcstats.atomicstarttotalsizebytes - g->gcstats.endtotalsizebytes) / duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void luaC_wakethread(lua_State* L)
|
void luaC_wakethread(lua_State* L)
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
|
|
||||||
#define luaC_checkGC(L) \
|
#define luaC_checkGC(L) \
|
||||||
{ \
|
{ \
|
||||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK))); \
|
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK)); \
|
||||||
if (L->global->totalbytes >= L->global->GCthreshold) \
|
if (L->global->totalbytes >= L->global->GCthreshold) \
|
||||||
{ \
|
{ \
|
||||||
condhardmemtests(luaC_validate(L), 1); \
|
condhardmemtests(luaC_validate(L), 1); \
|
||||||
|
|
|
@ -10,12 +10,12 @@ union GCObject;
|
||||||
#define luaM_newgco(L, t, size, memcat) cast_to(t*, luaM_newgco_(L, size, memcat))
|
#define luaM_newgco(L, t, size, memcat) cast_to(t*, luaM_newgco_(L, size, memcat))
|
||||||
#define luaM_freegco(L, p, size, memcat, page) luaM_freegco_(L, obj2gco(p), size, memcat, page)
|
#define luaM_freegco(L, p, size, memcat, page) luaM_freegco_(L, obj2gco(p), size, memcat, page)
|
||||||
|
|
||||||
#define luaM_arraysize_(n, e) ((cast_to(size_t, (n)) <= SIZE_MAX / (e)) ? (n) * (e) : (luaM_toobig(L), SIZE_MAX))
|
#define luaM_arraysize_(L, n, e) ((cast_to(size_t, (n)) <= SIZE_MAX / (e)) ? (n) * (e) : (luaM_toobig(L), SIZE_MAX))
|
||||||
|
|
||||||
#define luaM_newarray(L, n, t, memcat) cast_to(t*, luaM_new_(L, luaM_arraysize_(n, sizeof(t)), memcat))
|
#define luaM_newarray(L, n, t, memcat) cast_to(t*, luaM_new_(L, luaM_arraysize_(L, n, sizeof(t)), memcat))
|
||||||
#define luaM_freearray(L, b, n, t, memcat) luaM_free_(L, (b), (n) * sizeof(t), memcat)
|
#define luaM_freearray(L, b, n, t, memcat) luaM_free_(L, (b), (n) * sizeof(t), memcat)
|
||||||
#define luaM_reallocarray(L, v, oldn, n, t, memcat) \
|
#define luaM_reallocarray(L, v, oldn, n, t, memcat) \
|
||||||
((v) = cast_to(t*, luaM_realloc_(L, v, (oldn) * sizeof(t), luaM_arraysize_(n, sizeof(t)), memcat)))
|
((v) = cast_to(t*, luaM_realloc_(L, v, (oldn) * sizeof(t), luaM_arraysize_(L, n, sizeof(t)), memcat)))
|
||||||
|
|
||||||
LUAI_FUNC void* luaM_new_(lua_State* L, size_t nsize, uint8_t memcat);
|
LUAI_FUNC void* luaM_new_(lua_State* L, size_t nsize, uint8_t memcat);
|
||||||
LUAI_FUNC GCObject* luaM_newgco_(lua_State* L, size_t nsize, uint8_t memcat);
|
LUAI_FUNC GCObject* luaM_newgco_(lua_State* L, size_t nsize, uint8_t memcat);
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
#include "ldebug.h"
|
#include "ldebug.h"
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauReduceStackReallocs, false)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Main thread combines a thread state and the global state
|
** Main thread combines a thread state and the global state
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +33,7 @@ static void stack_init(lua_State* L1, lua_State* L)
|
||||||
for (int i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
for (int i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||||
setnilvalue(stack + i); /* erase new stack */
|
setnilvalue(stack + i); /* erase new stack */
|
||||||
L1->top = stack;
|
L1->top = stack;
|
||||||
L1->stack_last = stack + (L1->stacksize - (FFlag::LuauReduceStackReallocs ? EXTRA_STACK : 1 + EXTRA_STACK));
|
L1->stack_last = stack + (L1->stacksize - EXTRA_STACK);
|
||||||
/* initialize first ci */
|
/* initialize first ci */
|
||||||
L1->ci->func = L1->top;
|
L1->ci->func = L1->top;
|
||||||
setnilvalue(L1->top++); /* `function' entry for this `ci' */
|
setnilvalue(L1->top++); /* `function' entry for this `ci' */
|
||||||
|
@ -141,30 +139,16 @@ void lua_resetthread(lua_State* L)
|
||||||
ci->top = ci->base + LUA_MINSTACK;
|
ci->top = ci->base + LUA_MINSTACK;
|
||||||
setnilvalue(ci->func);
|
setnilvalue(ci->func);
|
||||||
L->ci = ci;
|
L->ci = ci;
|
||||||
if (FFlag::LuauReduceStackReallocs)
|
|
||||||
{
|
|
||||||
if (L->size_ci != BASIC_CI_SIZE)
|
if (L->size_ci != BASIC_CI_SIZE)
|
||||||
luaD_reallocCI(L, BASIC_CI_SIZE);
|
luaD_reallocCI(L, BASIC_CI_SIZE);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
luaD_reallocCI(L, BASIC_CI_SIZE);
|
|
||||||
}
|
|
||||||
/* clear thread state */
|
/* clear thread state */
|
||||||
L->status = LUA_OK;
|
L->status = LUA_OK;
|
||||||
L->base = L->ci->base;
|
L->base = L->ci->base;
|
||||||
L->top = L->ci->base;
|
L->top = L->ci->base;
|
||||||
L->nCcalls = L->baseCcalls = 0;
|
L->nCcalls = L->baseCcalls = 0;
|
||||||
/* clear thread stack */
|
/* clear thread stack */
|
||||||
if (FFlag::LuauReduceStackReallocs)
|
|
||||||
{
|
|
||||||
if (L->stacksize != BASIC_STACK_SIZE + EXTRA_STACK)
|
if (L->stacksize != BASIC_STACK_SIZE + EXTRA_STACK)
|
||||||
luaD_reallocstack(L, BASIC_STACK_SIZE);
|
luaD_reallocstack(L, BASIC_STACK_SIZE);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
luaD_reallocstack(L, BASIC_STACK_SIZE);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < L->stacksize; i++)
|
for (int i = 0; i < L->stacksize; i++)
|
||||||
setnilvalue(L->stack + i);
|
setnilvalue(L->stack + i);
|
||||||
}
|
}
|
||||||
|
@ -234,6 +218,10 @@ lua_State* lua_newstate(lua_Alloc f, void* ud)
|
||||||
g->cb = lua_Callbacks();
|
g->cb = lua_Callbacks();
|
||||||
g->gcstats = GCStats();
|
g->gcstats = GCStats();
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
|
g->gcmetrics = GCMetrics();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0)
|
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0)
|
||||||
{
|
{
|
||||||
/* memory allocation error: free partial state */
|
/* memory allocation error: free partial state */
|
||||||
|
|
|
@ -75,10 +75,26 @@ typedef struct CallInfo
|
||||||
#define f_isLua(ci) (!ci_func(ci)->isC)
|
#define f_isLua(ci) (!ci_func(ci)->isC)
|
||||||
#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci))
|
#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci))
|
||||||
|
|
||||||
struct GCCycleStats
|
struct GCStats
|
||||||
|
{
|
||||||
|
// data for proportional-integral controller of heap trigger value
|
||||||
|
int32_t triggerterms[32] = {0};
|
||||||
|
uint32_t triggertermpos = 0;
|
||||||
|
int32_t triggerintegral = 0;
|
||||||
|
|
||||||
|
size_t atomicstarttotalsizebytes = 0;
|
||||||
|
size_t endtotalsizebytes = 0;
|
||||||
|
size_t heapgoalsizebytes = 0;
|
||||||
|
|
||||||
|
double starttimestamp = 0;
|
||||||
|
double atomicstarttimestamp = 0;
|
||||||
|
double endtimestamp = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
|
struct GCCycleMetrics
|
||||||
{
|
{
|
||||||
size_t starttotalsizebytes = 0;
|
size_t starttotalsizebytes = 0;
|
||||||
size_t heapgoalsizebytes = 0;
|
|
||||||
size_t heaptriggersizebytes = 0;
|
size_t heaptriggersizebytes = 0;
|
||||||
|
|
||||||
double pausetime = 0.0; // time from end of the last cycle to the start of a new one
|
double pausetime = 0.0; // time from end of the last cycle to the start of a new one
|
||||||
|
@ -120,16 +136,7 @@ struct GCCycleStats
|
||||||
size_t endtotalsizebytes = 0;
|
size_t endtotalsizebytes = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// data for proportional-integral controller of heap trigger value
|
struct GCMetrics
|
||||||
struct GCHeapTriggerStats
|
|
||||||
{
|
|
||||||
static const unsigned termcount = 32;
|
|
||||||
int32_t terms[termcount] = {0};
|
|
||||||
uint32_t termpos = 0;
|
|
||||||
int32_t integral = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GCStats
|
|
||||||
{
|
{
|
||||||
double stepexplicittimeacc = 0.0;
|
double stepexplicittimeacc = 0.0;
|
||||||
double stepassisttimeacc = 0.0;
|
double stepassisttimeacc = 0.0;
|
||||||
|
@ -137,14 +144,10 @@ struct GCStats
|
||||||
// when cycle is completed, last cycle values are updated
|
// when cycle is completed, last cycle values are updated
|
||||||
uint64_t completedcycles = 0;
|
uint64_t completedcycles = 0;
|
||||||
|
|
||||||
GCCycleStats lastcycle;
|
GCCycleMetrics lastcycle;
|
||||||
GCCycleStats currcycle;
|
GCCycleMetrics currcycle;
|
||||||
|
|
||||||
// only step count and their time is accumulated
|
|
||||||
GCCycleStats cyclestatsacc;
|
|
||||||
|
|
||||||
GCHeapTriggerStats triggerstats;
|
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** `global state', shared by all threads of this state
|
** `global state', shared by all threads of this state
|
||||||
|
@ -206,6 +209,9 @@ typedef struct global_State
|
||||||
|
|
||||||
GCStats gcstats;
|
GCStats gcstats;
|
||||||
|
|
||||||
|
#ifdef LUAI_GCMETRICS
|
||||||
|
GCMetrics gcmetrics;
|
||||||
|
#endif
|
||||||
} global_State;
|
} global_State;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,26 @@
|
||||||
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
|
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Implementation of tables (aka arrays, objects, or hash tables).
|
* Implementation of tables (aka arrays, objects, or hash tables).
|
||||||
** Tables keep its elements in two parts: an array part and a hash part.
|
*
|
||||||
** Non-negative integer keys are all candidates to be kept in the array
|
* Tables keep the elements in two parts: an array part and a hash part.
|
||||||
** part. The actual size of the array is the largest `n' such that at
|
* Integer keys >=1 are all candidates to be kept in the array part. The actual size of the array is the
|
||||||
** least half the slots between 0 and n are in use.
|
* largest n such that at least half the slots between 0 and n are in use.
|
||||||
** Hash uses a mix of chained scatter table with Brent's variation.
|
* Hash uses a mix of chained scatter table with Brent's variation.
|
||||||
** A main invariant of these tables is that, if an element is not
|
*
|
||||||
** in its main position (i.e. the `original' position that its hash gives
|
* A main invariant of these tables is that, if an element is not in its main position (i.e. the original
|
||||||
** to it), then the colliding element is in its own main position.
|
* position that its hash gives to it), then the colliding element is in its own main position.
|
||||||
** Hence even when the load factor reaches 100%, performance remains good.
|
* Hence even when the load factor reaches 100%, performance remains good.
|
||||||
*/
|
*
|
||||||
|
* Table keys can be arbitrary values unless they contain NaN. Keys are hashed and compared using raw equality,
|
||||||
|
* so even if the key is a userdata with an overridden __eq, it's not used during hash lookups.
|
||||||
|
*
|
||||||
|
* Each table has a "boundary", defined as the index k where t[k] ~= nil and t[k+1] == nil. The boundary can be
|
||||||
|
* computed using a binary search and can be adjusted when the table is modified; crucially, Luau enforces an
|
||||||
|
* invariant where the boundary must be in the array part - this enforces a consistent iteration order through the
|
||||||
|
* prefix of the table when using pairs(), and allows to implement algorithms that access elements in 1..#t range
|
||||||
|
* more efficiently.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "ltable.h"
|
#include "ltable.h"
|
||||||
|
|
||||||
|
@ -25,6 +34,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTableRehashRework, false)
|
LUAU_FASTFLAGVARIABLE(LuauTableRehashRework, false)
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauTableNewBoundary, false)
|
||||||
|
|
||||||
// max size of both array and hash part is 2^MAXBITS
|
// max size of both array and hash part is 2^MAXBITS
|
||||||
#define MAXBITS 26
|
#define MAXBITS 26
|
||||||
|
@ -460,7 +470,20 @@ static void rehash(lua_State* L, Table* t, const TValue* ek)
|
||||||
totaluse++;
|
totaluse++;
|
||||||
/* compute new size for array part */
|
/* compute new size for array part */
|
||||||
int na = computesizes(nums, &nasize);
|
int na = computesizes(nums, &nasize);
|
||||||
|
/* enforce the boundary invariant; for performance, only do hash lookups if we must */
|
||||||
|
if (FFlag::LuauTableNewBoundary)
|
||||||
|
{
|
||||||
|
bool tbound = t->node != dummynode || nasize < t->sizearray;
|
||||||
|
int ekindex = ttisnumber(ek) ? arrayindex(nvalue(ek)) : -1;
|
||||||
|
/* move the array size up until the boundary is guaranteed to be inside the array part */
|
||||||
|
while (nasize + 1 == ekindex || (tbound && !ttisnil(luaH_getnum(t, nasize + 1))))
|
||||||
|
{
|
||||||
|
nasize++;
|
||||||
|
na++;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* resize the table to new computed sizes */
|
/* resize the table to new computed sizes */
|
||||||
|
LUAU_ASSERT(na <= totaluse);
|
||||||
resize(L, t, nasize, totaluse - na);
|
resize(L, t, nasize, totaluse - na);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,10 +543,18 @@ static LuaNode* getfreepos(Table* t)
|
||||||
*/
|
*/
|
||||||
static TValue* newkey(lua_State* L, Table* t, const TValue* key)
|
static TValue* newkey(lua_State* L, Table* t, const TValue* key)
|
||||||
{
|
{
|
||||||
|
/* enforce boundary invariant */
|
||||||
|
if (FFlag::LuauTableNewBoundary && ttisnumber(key) && nvalue(key) == t->sizearray + 1)
|
||||||
|
{
|
||||||
|
rehash(L, t, key); /* grow table */
|
||||||
|
|
||||||
|
// after rehash, numeric keys might be located in the new array part, but won't be found in the node part
|
||||||
|
return arrayornewkey(L, t, key);
|
||||||
|
}
|
||||||
|
|
||||||
LuaNode* mp = mainposition(t, key);
|
LuaNode* mp = mainposition(t, key);
|
||||||
if (!ttisnil(gval(mp)) || mp == dummynode)
|
if (!ttisnil(gval(mp)) || mp == dummynode)
|
||||||
{
|
{
|
||||||
LuaNode* othern;
|
|
||||||
LuaNode* n = getfreepos(t); /* get a free place */
|
LuaNode* n = getfreepos(t); /* get a free place */
|
||||||
if (n == NULL)
|
if (n == NULL)
|
||||||
{ /* cannot find a free place? */
|
{ /* cannot find a free place? */
|
||||||
|
@ -542,7 +573,7 @@ static TValue* newkey(lua_State* L, Table* t, const TValue* key)
|
||||||
LUAU_ASSERT(n != dummynode);
|
LUAU_ASSERT(n != dummynode);
|
||||||
TValue mk;
|
TValue mk;
|
||||||
getnodekey(L, &mk, mp);
|
getnodekey(L, &mk, mp);
|
||||||
othern = mainposition(t, &mk);
|
LuaNode* othern = mainposition(t, &mk);
|
||||||
if (othern != mp)
|
if (othern != mp)
|
||||||
{ /* is colliding node out of its main position? */
|
{ /* is colliding node out of its main position? */
|
||||||
/* yes; move colliding node into free position */
|
/* yes; move colliding node into free position */
|
||||||
|
@ -704,6 +735,7 @@ TValue* luaH_setstr(lua_State* L, Table* t, TString* key)
|
||||||
|
|
||||||
static LUAU_NOINLINE int unbound_search(Table* t, unsigned int j)
|
static LUAU_NOINLINE int unbound_search(Table* t, unsigned int j)
|
||||||
{
|
{
|
||||||
|
LUAU_ASSERT(!FFlag::LuauTableNewBoundary);
|
||||||
unsigned int i = j; /* i is zero or a present index */
|
unsigned int i = j; /* i is zero or a present index */
|
||||||
j++;
|
j++;
|
||||||
/* find `i' and `j' such that i is present and j is not */
|
/* find `i' and `j' such that i is present and j is not */
|
||||||
|
@ -788,6 +820,12 @@ int luaH_getn(Table* t)
|
||||||
maybesetaboundary(t, boundary);
|
maybesetaboundary(t, boundary);
|
||||||
return boundary;
|
return boundary;
|
||||||
}
|
}
|
||||||
|
else if (FFlag::LuauTableNewBoundary)
|
||||||
|
{
|
||||||
|
/* validate boundary invariant */
|
||||||
|
LUAU_ASSERT(t->node == dummynode || ttisnil(luaH_getnum(t, j + 1)));
|
||||||
|
return j;
|
||||||
|
}
|
||||||
/* else must find a boundary in hash part */
|
/* else must find a boundary in hash part */
|
||||||
else if (t->node == dummynode) /* hash part is empty? */
|
else if (t->node == dummynode) /* hash part is empty? */
|
||||||
return j; /* that is easy... */
|
return j; /* that is easy... */
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#include "ldebug.h"
|
#include "ldebug.h"
|
||||||
#include "lvm.h"
|
#include "lvm.h"
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTableClone, false)
|
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauTableMoveTelemetry2, false)
|
||||||
|
|
||||||
|
void (*lua_table_move_telemetry)(lua_State* L, int f, int e, int t, int nf, int nt);
|
||||||
|
|
||||||
static int foreachi(lua_State* L)
|
static int foreachi(lua_State* L)
|
||||||
{
|
{
|
||||||
|
@ -197,6 +199,29 @@ static int tmove(lua_State* L)
|
||||||
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
|
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
|
||||||
luaL_checktype(L, tt, LUA_TTABLE);
|
luaL_checktype(L, tt, LUA_TTABLE);
|
||||||
|
|
||||||
|
void (*telemetrycb)(lua_State* L, int f, int e, int t, int nf, int nt) = lua_table_move_telemetry;
|
||||||
|
|
||||||
|
if (DFFlag::LuauTableMoveTelemetry2 && telemetrycb)
|
||||||
|
{
|
||||||
|
int nf = lua_objlen(L, 1);
|
||||||
|
int nt = lua_objlen(L, tt);
|
||||||
|
|
||||||
|
bool report = false;
|
||||||
|
|
||||||
|
// source index range must be in bounds in source table unless the table is empty (permits 1..#t moves)
|
||||||
|
if (!(f == 1 || (f >= 1 && f <= nf)))
|
||||||
|
report = true;
|
||||||
|
if (!(e == nf || (e >= 1 && e <= nf)))
|
||||||
|
report = true;
|
||||||
|
|
||||||
|
// destination index must be in bounds in dest table or be exactly at the first empty element (permits concats)
|
||||||
|
if (!(t == nt + 1 || (t >= 1 && t <= nt)))
|
||||||
|
report = true;
|
||||||
|
|
||||||
|
if (report)
|
||||||
|
telemetrycb(L, f, e, t, nf, nt);
|
||||||
|
}
|
||||||
|
|
||||||
if (e >= f)
|
if (e >= f)
|
||||||
{ /* otherwise, nothing to move */
|
{ /* otherwise, nothing to move */
|
||||||
luaL_argcheck(L, f > 0 || e < INT_MAX + f, 3, "too many elements to move");
|
luaL_argcheck(L, f > 0 || e < INT_MAX + f, 3, "too many elements to move");
|
||||||
|
@ -512,9 +537,6 @@ static int tisfrozen(lua_State* L)
|
||||||
|
|
||||||
static int tclone(lua_State* L)
|
static int tclone(lua_State* L)
|
||||||
{
|
{
|
||||||
if (!FFlag::LuauTableClone)
|
|
||||||
luaG_runerror(L, "table.clone is not available");
|
|
||||||
|
|
||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
luaL_argcheck(L, !luaL_getmetafield(L, 1, "__metatable"), 1, "table has a protected metatable");
|
luaL_argcheck(L, !luaL_getmetafield(L, 1, "__metatable"), 1, "table has a protected metatable");
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
LUAU_FASTFLAG(LuauTableNewBoundary)
|
||||||
|
|
||||||
// Disable c99-designator to avoid the warning in CGOTO dispatch table
|
// Disable c99-designator to avoid the warning in CGOTO dispatch table
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#if __has_warning("-Wc99-designator")
|
#if __has_warning("-Wc99-designator")
|
||||||
|
@ -2266,9 +2268,9 @@ static void luau_execute(lua_State* L)
|
||||||
VM_NEXT();
|
VM_NEXT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (h->lsizenode == 0 && ttisnil(gval(h->node)))
|
else if (FFlag::LuauTableNewBoundary || (h->lsizenode == 0 && ttisnil(gval(h->node))))
|
||||||
{
|
{
|
||||||
// hash part is empty: fallthrough to exit
|
// fallthrough to exit
|
||||||
VM_NEXT();
|
VM_NEXT();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauBytecodeV2Force, false)
|
|
||||||
|
|
||||||
// TODO: RAII deallocation doesn't work for longjmp builds if a memory error happens
|
// TODO: RAII deallocation doesn't work for longjmp builds if a memory error happens
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct TempBuffer
|
struct TempBuffer
|
||||||
|
@ -156,12 +154,11 @@ int luau_load(lua_State* L, const char* chunkname, const char* data, size_t size
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauBytecodeV2Force ? (version != LBC_VERSION_FUTURE) : (version != LBC_VERSION && version != LBC_VERSION_FUTURE))
|
if (version != LBC_VERSION)
|
||||||
{
|
{
|
||||||
char chunkid[LUA_IDSIZE];
|
char chunkid[LUA_IDSIZE];
|
||||||
luaO_chunkid(chunkid, chunkname, LUA_IDSIZE);
|
luaO_chunkid(chunkid, chunkname, LUA_IDSIZE);
|
||||||
lua_pushfstring(L, "%s: bytecode version mismatch (expected %d, got %d)", chunkid,
|
lua_pushfstring(L, "%s: bytecode version mismatch (expected %d, got %d)", chunkid, LBC_VERSION, version);
|
||||||
FFlag::LuauBytecodeV2Force ? LBC_VERSION_FUTURE : LBC_VERSION, version);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,11 +289,7 @@ int luau_load(lua_State* L, const char* chunkname, const char* data, size_t size
|
||||||
p->p[j] = protos[fid];
|
p->p[j] = protos[fid];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauBytecodeV2Force || version == LBC_VERSION_FUTURE)
|
|
||||||
p->linedefined = readVarInt(data, size, offset);
|
p->linedefined = readVarInt(data, size, offset);
|
||||||
else
|
|
||||||
p->linedefined = -1;
|
|
||||||
|
|
||||||
p->debugname = readString(strings, data, size, offset);
|
p->debugname = readString(strings, data, size, offset);
|
||||||
|
|
||||||
uint8_t lineinfo = read<uint8_t>(data, size, offset);
|
uint8_t lineinfo = read<uint8_t>(data, size, offset);
|
||||||
|
|
|
@ -111,7 +111,6 @@ impl Build {
|
||||||
.clone()
|
.clone()
|
||||||
.include(&vm_include_dir)
|
.include(&vm_include_dir)
|
||||||
.define("LUA_API", "extern \"C\"")
|
.define("LUA_API", "extern \"C\"")
|
||||||
// Works 9 times slower, see https://github.com/Roblox/luau/issues/425
|
|
||||||
// .define("LUA_USE_LONGJMP", "1")
|
// .define("LUA_USE_LONGJMP", "1")
|
||||||
.add_files_by_ext(&vm_source_dir, "cpp")
|
.add_files_by_ext(&vm_source_dir, "cpp")
|
||||||
.out_dir(&lib_dir)
|
.out_dir(&lib_dir)
|
||||||
|
|
Loading…
Reference in New Issue