v0.5.3+luau566
This commit is contained in:
parent
11712dae9e
commit
abce01e607
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "luau0-src"
|
||||
version = "0.5.2+luau561"
|
||||
version = "0.5.3+luau566"
|
||||
authors = ["Aleksandr Orlenko <zxteam@protonmail.com>"]
|
||||
edition = "2021"
|
||||
repository = "https://github.com/khvzak/luau-src-rs"
|
||||
|
|
|
@ -251,7 +251,6 @@ enum class ConstantNumberParseResult
|
|||
Malformed,
|
||||
BinOverflow,
|
||||
HexOverflow,
|
||||
DoublePrefix,
|
||||
};
|
||||
|
||||
class AstExprConstantNumber : public AstExpr
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixInterpStringMid, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -640,7 +642,8 @@ Lexeme Lexer::readInterpolatedStringSection(Position start, Lexeme::Type formatT
|
|||
}
|
||||
|
||||
consume();
|
||||
Lexeme lexemeOutput(Location(start, position()), Lexeme::InterpStringBegin, &buffer[startOffset], offset - startOffset - 1);
|
||||
Lexeme lexemeOutput(Location(start, position()), FFlag::LuauFixInterpStringMid ? formatType : Lexeme::InterpStringBegin,
|
||||
&buffer[startOffset], offset - startOffset - 1);
|
||||
return lexemeOutput;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,15 +14,8 @@
|
|||
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
||||
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorDoubleHexPrefix, false)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauParserErrorsOnMissingDefaultTypePackArgument, false)
|
||||
|
||||
bool lua_telemetry_parsed_out_of_range_bin_integer = false;
|
||||
bool lua_telemetry_parsed_out_of_range_hex_integer = false;
|
||||
bool lua_telemetry_parsed_double_prefix_hex_integer = false;
|
||||
|
||||
#define ERROR_INVALID_INTERP_DOUBLE_BRACE "Double braces are not permitted within interpolated strings. Did you mean '\\{'?"
|
||||
|
||||
namespace Luau
|
||||
|
@ -1255,7 +1248,11 @@ std::pair<Location, AstTypeList> Parser::parseReturnTypeAnnotation()
|
|||
{
|
||||
AstType* returnType = parseTypeAnnotation(result, innerBegin);
|
||||
|
||||
return {Location{location, returnType->location}, AstTypeList{copy(&returnType, 1), varargAnnotation}};
|
||||
// If parseTypeAnnotation parses nothing, then returnType->location.end only points at the last non-type-pack
|
||||
// type to successfully parse. We need the span of the whole annotation.
|
||||
Position endPos = result.size() == 1 ? location.end : returnType->location.end;
|
||||
|
||||
return {Location{location.begin, endPos}, AstTypeList{copy(&returnType, 1), varargAnnotation}};
|
||||
}
|
||||
|
||||
return {location, AstTypeList{copy(result), varargAnnotation}};
|
||||
|
@ -2093,17 +2090,7 @@ static ConstantNumberParseResult parseInteger(double& result, const char* data,
|
|||
value = strtoull(data, &end, base);
|
||||
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
if (DFFlag::LuaReportParseIntegerIssues)
|
||||
{
|
||||
if (base == 2)
|
||||
lua_telemetry_parsed_out_of_range_bin_integer = true;
|
||||
else
|
||||
lua_telemetry_parsed_out_of_range_hex_integer = true;
|
||||
}
|
||||
|
||||
return base == 2 ? ConstantNumberParseResult::BinOverflow : ConstantNumberParseResult::HexOverflow;
|
||||
}
|
||||
}
|
||||
|
||||
return ConstantNumberParseResult::Ok;
|
||||
|
@ -2117,18 +2104,7 @@ static ConstantNumberParseResult parseDouble(double& result, const char* data)
|
|||
|
||||
// hexadecimal literal
|
||||
if (data[0] == '0' && (data[1] == 'x' || data[1] == 'X') && data[2])
|
||||
{
|
||||
if (!FFlag::LuauErrorDoubleHexPrefix && data[2] == '0' && (data[3] == 'x' || data[3] == 'X'))
|
||||
{
|
||||
if (DFFlag::LuaReportParseIntegerIssues)
|
||||
lua_telemetry_parsed_double_prefix_hex_integer = true;
|
||||
|
||||
ConstantNumberParseResult parseResult = parseInteger(result, data + 2, 16);
|
||||
return parseResult == ConstantNumberParseResult::Malformed ? parseResult : ConstantNumberParseResult::DoublePrefix;
|
||||
}
|
||||
|
||||
return parseInteger(result, data, 16); // pass in '0x' prefix, it's handled by 'strtoull'
|
||||
}
|
||||
|
||||
char* end = nullptr;
|
||||
double value = strtod(data, &end);
|
||||
|
@ -2651,8 +2627,6 @@ AstExpr* Parser::parseInterpString()
|
|||
|
||||
endLocation = currentLexeme.location;
|
||||
|
||||
Location startOfBrace = Location(endLocation.end, 1);
|
||||
|
||||
scratchData.assign(currentLexeme.data, currentLexeme.length);
|
||||
|
||||
if (!Lexer::fixupQuotedString(scratchData))
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
// Upvalues: 0-254. Upvalues refer to the values stored in the closure object.
|
||||
// Constants: 0-2^23-1. Constants are stored in a table allocated with each proto; to allow for future bytecode tweaks the encodable value is limited to 23 bits.
|
||||
// Closures: 0-2^15-1. Closures are created from child protos via a child index; the limit is for the number of closures immediately referenced in each function.
|
||||
// Jumps: -2^23..2^23. Jump offsets are specified in word increments, so jumping over an instruction may sometimes require an offset of 2 or more.
|
||||
// Jumps: -2^23..2^23. Jump offsets are specified in word increments, so jumping over an instruction may sometimes require an offset of 2 or more. Note that for jump instructions with AUX, the AUX word is included as part of the jump offset.
|
||||
|
||||
// # Bytecode versions
|
||||
// Bytecode serialized format embeds a version number, that dictates both the serialized form as well as the allowed instructions. As long as the bytecode version falls into supported
|
||||
|
@ -42,7 +42,7 @@
|
|||
// Note: due to limitations of the versioning scheme, some bytecode blobs that carry version 2 are using features from version 3. Starting from version 3, version should be sufficient to indicate bytecode compatibility.
|
||||
//
|
||||
// Version 1: Baseline version for the open-source release. Supported until 0.521.
|
||||
// Version 2: Adds Proto::linedefined. Currently supported.
|
||||
// Version 2: Adds Proto::linedefined. Supported until 0.544.
|
||||
// Version 3: Adds FORGPREP/JUMPXEQK* and enhances AUX encoding for FORGLOOP. Removes FORGLOOP_NEXT/INEXT and JUMPIFEQK/JUMPIFNOTEQK. Currently supported.
|
||||
|
||||
// Bytecode opcode, part of the instruction header
|
||||
|
@ -194,7 +194,7 @@ enum LuauOpcode
|
|||
|
||||
// JUMPIFEQ, JUMPIFLE, JUMPIFLT, JUMPIFNOTEQ, JUMPIFNOTLE, JUMPIFNOTLT: jumps to target offset if the comparison is true (or false, for NOT variants)
|
||||
// A: source register 1
|
||||
// D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump")
|
||||
// D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump")
|
||||
// AUX: source register 2
|
||||
LOP_JUMPIFEQ,
|
||||
LOP_JUMPIFLE,
|
||||
|
@ -376,14 +376,14 @@ enum LuauOpcode
|
|||
|
||||
// JUMPXEQKNIL, JUMPXEQKB: jumps to target offset if the comparison with constant is true (or false, see AUX)
|
||||
// A: source register 1
|
||||
// D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump")
|
||||
// D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump")
|
||||
// AUX: constant value (for boolean) in low bit, NOT flag (that flips comparison result) in high bit
|
||||
LOP_JUMPXEQKNIL,
|
||||
LOP_JUMPXEQKB,
|
||||
|
||||
// JUMPXEQKN, JUMPXEQKS: jumps to target offset if the comparison with constant is true (or false, see AUX)
|
||||
// A: source register 1
|
||||
// D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump")
|
||||
// D: jump offset (-32768..32767; 1 means "next instruction" aka "don't jump")
|
||||
// AUX: constant table index in low 24 bits, NOT flag (that flips comparison result) in high bit
|
||||
LOP_JUMPXEQKN,
|
||||
LOP_JUMPXEQKS,
|
||||
|
|
|
@ -10,9 +10,10 @@ inline bool isFlagExperimental(const char* flag)
|
|||
{
|
||||
// Flags in this list are disabled by default in various command-line tools. They may have behavior that is not fully final,
|
||||
// or critical bugs that are found after the code has been submitted.
|
||||
static const char* kList[] = {
|
||||
static const char* const kList[] = {
|
||||
"LuauInstantiateInSubtyping", // requires some fixes to lua-apps code
|
||||
"LuauTryhardAnd", // waiting for a fix in graphql-lua -> apollo-client-lia -> lua-apps
|
||||
"LuauTypecheckTypeguards", // requires some fixes to lua-apps code (CLI-67030)
|
||||
// makes sure we always have at least one entry
|
||||
nullptr,
|
||||
};
|
||||
|
|
|
@ -244,5 +244,158 @@ void analyzeBuiltins(DenseHashMap<AstExprCall*, int>& result, const DenseHashMap
|
|||
root->visit(&visitor);
|
||||
}
|
||||
|
||||
BuiltinInfo getBuiltinInfo(int bfid)
|
||||
{
|
||||
switch (LuauBuiltinFunction(bfid))
|
||||
{
|
||||
case LBF_NONE:
|
||||
return {-1, -1};
|
||||
|
||||
case LBF_ASSERT:
|
||||
return {-1, -1};
|
||||
; // assert() returns all values when first value is truthy
|
||||
|
||||
case LBF_MATH_ABS:
|
||||
case LBF_MATH_ACOS:
|
||||
case LBF_MATH_ASIN:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_MATH_ATAN2:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_MATH_ATAN:
|
||||
case LBF_MATH_CEIL:
|
||||
case LBF_MATH_COSH:
|
||||
case LBF_MATH_COS:
|
||||
case LBF_MATH_DEG:
|
||||
case LBF_MATH_EXP:
|
||||
case LBF_MATH_FLOOR:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_MATH_FMOD:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_MATH_FREXP:
|
||||
return {1, 2};
|
||||
|
||||
case LBF_MATH_LDEXP:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_MATH_LOG10:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_MATH_LOG:
|
||||
return {-1, 1}; // 1 or 2 parameters
|
||||
|
||||
case LBF_MATH_MAX:
|
||||
case LBF_MATH_MIN:
|
||||
return {-1, 1}; // variadic
|
||||
|
||||
case LBF_MATH_MODF:
|
||||
return {1, 2};
|
||||
|
||||
case LBF_MATH_POW:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_MATH_RAD:
|
||||
case LBF_MATH_SINH:
|
||||
case LBF_MATH_SIN:
|
||||
case LBF_MATH_SQRT:
|
||||
case LBF_MATH_TANH:
|
||||
case LBF_MATH_TAN:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_BIT32_ARSHIFT:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_BIT32_BAND:
|
||||
return {-1, 1}; // variadic
|
||||
|
||||
case LBF_BIT32_BNOT:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_BIT32_BOR:
|
||||
case LBF_BIT32_BXOR:
|
||||
case LBF_BIT32_BTEST:
|
||||
return {-1, 1}; // variadic
|
||||
|
||||
case LBF_BIT32_EXTRACT:
|
||||
return {-1, 1}; // 2 or 3 parameters
|
||||
|
||||
case LBF_BIT32_LROTATE:
|
||||
case LBF_BIT32_LSHIFT:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_BIT32_REPLACE:
|
||||
return {-1, 1}; // 3 or 4 parameters
|
||||
|
||||
case LBF_BIT32_RROTATE:
|
||||
case LBF_BIT32_RSHIFT:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_TYPE:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_STRING_BYTE:
|
||||
return {-1, -1}; // 1, 2 or 3 parameters
|
||||
|
||||
case LBF_STRING_CHAR:
|
||||
return {-1, 1}; // variadic
|
||||
|
||||
case LBF_STRING_LEN:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_TYPEOF:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_STRING_SUB:
|
||||
return {-1, 1}; // 2 or 3 parameters
|
||||
|
||||
case LBF_MATH_CLAMP:
|
||||
return {3, 1};
|
||||
|
||||
case LBF_MATH_SIGN:
|
||||
case LBF_MATH_ROUND:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_RAWSET:
|
||||
return {3, 1};
|
||||
|
||||
case LBF_RAWGET:
|
||||
case LBF_RAWEQUAL:
|
||||
return {2, 1};
|
||||
|
||||
case LBF_TABLE_INSERT:
|
||||
return {-1, 0}; // 2 or 3 parameters
|
||||
|
||||
case LBF_TABLE_UNPACK:
|
||||
return {-1, -1}; // 1, 2 or 3 parameters
|
||||
|
||||
case LBF_VECTOR:
|
||||
return {-1, 1}; // 3 or 4 parameters in some configurations
|
||||
|
||||
case LBF_BIT32_COUNTLZ:
|
||||
case LBF_BIT32_COUNTRZ:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_SELECT_VARARG:
|
||||
return {-1, -1}; // variadic
|
||||
|
||||
case LBF_RAWLEN:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_BIT32_EXTRACTK:
|
||||
return {3, 1};
|
||||
|
||||
case LBF_GETMETATABLE:
|
||||
return {1, 1};
|
||||
|
||||
case LBF_SETMETATABLE:
|
||||
return {2, 1};
|
||||
};
|
||||
|
||||
LUAU_UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Compile
|
||||
} // namespace Luau
|
||||
|
|
|
@ -39,5 +39,13 @@ Builtin getBuiltin(AstExpr* node, const DenseHashMap<AstName, Global>& globals,
|
|||
void analyzeBuiltins(DenseHashMap<AstExprCall*, int>& result, const DenseHashMap<AstName, Global>& globals,
|
||||
const DenseHashMap<AstLocal*, Variable>& variables, const CompileOptions& options, AstNode* root);
|
||||
|
||||
struct BuiltinInfo
|
||||
{
|
||||
int params;
|
||||
int results;
|
||||
};
|
||||
|
||||
BuiltinInfo getBuiltinInfo(int bfid);
|
||||
|
||||
} // namespace Compile
|
||||
} // namespace Luau
|
||||
|
|
|
@ -2038,7 +2038,10 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result,
|
|||
|
||||
case LOP_CAPTURE:
|
||||
formatAppend(result, "CAPTURE %s %c%d\n",
|
||||
LUAU_INSN_A(insn) == LCT_UPVAL ? "UPVAL" : LUAU_INSN_A(insn) == LCT_REF ? "REF" : LUAU_INSN_A(insn) == LCT_VAL ? "VAL" : "",
|
||||
LUAU_INSN_A(insn) == LCT_UPVAL ? "UPVAL"
|
||||
: LUAU_INSN_A(insn) == LCT_REF ? "REF"
|
||||
: LUAU_INSN_A(insn) == LCT_VAL ? "VAL"
|
||||
: "",
|
||||
LUAU_INSN_A(insn) == LCT_UPVAL ? 'U' : 'R', LUAU_INSN_B(insn));
|
||||
break;
|
||||
|
||||
|
|
|
@ -25,9 +25,8 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25)
|
|||
LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
|
||||
LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauMultiAssignmentConflictFix, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSelfAssignmentSkip, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileInterpStringLimit, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileTerminateBC, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileBuiltinArity, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -136,14 +135,18 @@ struct Compiler
|
|||
return uint8_t(upvals.size() - 1);
|
||||
}
|
||||
|
||||
bool allPathsEndWithReturn(AstStat* node)
|
||||
// true iff all execution paths through node subtree result in return/break/continue
|
||||
// note: because this function doesn't visit loop nodes, it (correctly) only detects break/continue that refer to the outer control flow
|
||||
bool alwaysTerminates(AstStat* node)
|
||||
{
|
||||
if (AstStatBlock* stat = node->as<AstStatBlock>())
|
||||
return stat->body.size > 0 && allPathsEndWithReturn(stat->body.data[stat->body.size - 1]);
|
||||
return stat->body.size > 0 && alwaysTerminates(stat->body.data[stat->body.size - 1]);
|
||||
else if (node->is<AstStatReturn>())
|
||||
return true;
|
||||
else if (FFlag::LuauCompileTerminateBC && (node->is<AstStatBreak>() || node->is<AstStatContinue>()))
|
||||
return true;
|
||||
else if (AstStatIf* stat = node->as<AstStatIf>())
|
||||
return stat->elsebody && allPathsEndWithReturn(stat->thenbody) && allPathsEndWithReturn(stat->elsebody);
|
||||
return stat->elsebody && alwaysTerminates(stat->thenbody) && alwaysTerminates(stat->elsebody);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -217,7 +220,7 @@ struct Compiler
|
|||
|
||||
// valid function bytecode must always end with RETURN
|
||||
// we elide this if we're guaranteed to hit a RETURN statement regardless of the control flow
|
||||
if (!allPathsEndWithReturn(stat))
|
||||
if (!alwaysTerminates(stat))
|
||||
{
|
||||
setDebugLineEnd(stat);
|
||||
closeLocals(0);
|
||||
|
@ -261,7 +264,7 @@ struct Compiler
|
|||
f.costModel = modelCost(func->body, func->args.data, func->args.size, builtins);
|
||||
|
||||
// track functions that only ever return a single value so that we can convert multret calls to fixedret calls
|
||||
if (allPathsEndWithReturn(func->body))
|
||||
if (alwaysTerminates(func->body))
|
||||
{
|
||||
ReturnVisitor returnVisitor(this);
|
||||
stat->visit(&returnVisitor);
|
||||
|
@ -291,6 +294,12 @@ struct Compiler
|
|||
if (isConstant(expr))
|
||||
return false;
|
||||
|
||||
// handles builtin calls that can't be constant-folded but are known to return one value
|
||||
// note: optimizationLevel check is technically redundant but it's important that we never optimize based on builtins in O1
|
||||
if (FFlag::LuauCompileBuiltinArity && options.optimizationLevel >= 2)
|
||||
if (int* bfid = builtins.find(expr))
|
||||
return getBuiltinInfo(*bfid).results != 1;
|
||||
|
||||
// handles local function calls where we know only one argument is returned
|
||||
AstExprFunction* func = getFunctionExpr(expr->func);
|
||||
Function* fi = func ? functions.find(func) : nullptr;
|
||||
|
@ -504,6 +513,7 @@ struct Compiler
|
|||
// we can't inline multret functions because the caller expects L->top to be adjusted:
|
||||
// - inlined return compiles to a JUMP, and we don't have an instruction that adjusts L->top arbitrarily
|
||||
// - even if we did, right now all L->top adjustments are immediately consumed by the next instruction, and for now we want to preserve that
|
||||
// - additionally, we can't easily compile multret expressions into designated target as computed call arguments will get clobbered
|
||||
if (multRet)
|
||||
{
|
||||
bytecode.addDebugRemark("inlining failed: can't convert fixed returns to multret");
|
||||
|
@ -644,7 +654,7 @@ struct Compiler
|
|||
}
|
||||
|
||||
// for the fallthrough path we need to ensure we clear out target registers
|
||||
if (!usedFallthrough && !allPathsEndWithReturn(func->body))
|
||||
if (!usedFallthrough && !alwaysTerminates(func->body))
|
||||
{
|
||||
for (size_t i = 0; i < targetCount; ++i)
|
||||
bytecode.emitABC(LOP_LOADNIL, uint8_t(target + i), 0, 0);
|
||||
|
@ -753,8 +763,13 @@ struct Compiler
|
|||
}
|
||||
|
||||
// Optimization: for 1/2 argument fast calls use specialized opcodes
|
||||
if (bfid >= 0 && expr->args.size >= 1 && expr->args.size <= 2 && !isExprMultRet(expr->args.data[expr->args.size - 1]))
|
||||
return compileExprFastcallN(expr, target, targetCount, targetTop, multRet, regs, bfid);
|
||||
if (bfid >= 0 && expr->args.size >= 1 && expr->args.size <= 2)
|
||||
{
|
||||
if (!isExprMultRet(expr->args.data[expr->args.size - 1]))
|
||||
return compileExprFastcallN(expr, target, targetCount, targetTop, multRet, regs, bfid);
|
||||
else if (FFlag::LuauCompileBuiltinArity && options.optimizationLevel >= 2 && int(expr->args.size) == getBuiltinInfo(bfid).params)
|
||||
return compileExprFastcallN(expr, target, targetCount, targetTop, multRet, regs, bfid);
|
||||
}
|
||||
|
||||
if (expr->self)
|
||||
{
|
||||
|
@ -1580,8 +1595,7 @@ struct Compiler
|
|||
|
||||
RegScope rs(this);
|
||||
|
||||
uint8_t baseReg = FFlag::LuauCompileInterpStringLimit ? allocReg(expr, unsigned(2 + expr->expressions.size))
|
||||
: allocReg(expr, uint8_t(2 + expr->expressions.size));
|
||||
uint8_t baseReg = allocReg(expr, unsigned(2 + expr->expressions.size));
|
||||
|
||||
emitLoadK(baseReg, formatStringIndex);
|
||||
|
||||
|
@ -2030,7 +2044,7 @@ struct Compiler
|
|||
if (int reg = getExprLocalReg(expr); reg >= 0)
|
||||
{
|
||||
// Optimization: we don't need to move if target happens to be in the same register
|
||||
if (!FFlag::LuauSelfAssignmentSkip || options.optimizationLevel == 0 || target != reg)
|
||||
if (options.optimizationLevel == 0 || target != reg)
|
||||
bytecode.emitABC(LOP_MOVE, target, uint8_t(reg), 0);
|
||||
}
|
||||
else
|
||||
|
@ -2440,9 +2454,9 @@ struct Compiler
|
|||
|
||||
if (stat->elsebody && elseJump.size() > 0)
|
||||
{
|
||||
// we don't need to skip past "else" body if "then" ends with return
|
||||
// we don't need to skip past "else" body if "then" ends with return/break/continue
|
||||
// this is important because, if "else" also ends with return, we may *not* have any statement to skip to!
|
||||
if (allPathsEndWithReturn(stat->thenbody))
|
||||
if (alwaysTerminates(stat->thenbody))
|
||||
{
|
||||
size_t elseLabel = bytecode.emitLabel();
|
||||
|
||||
|
@ -2982,48 +2996,31 @@ struct Compiler
|
|||
|
||||
Visitor visitor(this);
|
||||
|
||||
if (FFlag::LuauMultiAssignmentConflictFix)
|
||||
// mark any registers that are used *after* assignment as conflicting
|
||||
|
||||
// first we go through assignments to locals, since they are performed before assignments to other l-values
|
||||
for (size_t i = 0; i < vars.size(); ++i)
|
||||
{
|
||||
// mark any registers that are used *after* assignment as conflicting
|
||||
const LValue& li = vars[i].lvalue;
|
||||
|
||||
// first we go through assignments to locals, since they are performed before assignments to other l-values
|
||||
for (size_t i = 0; i < vars.size(); ++i)
|
||||
if (li.kind == LValue::Kind_Local)
|
||||
{
|
||||
const LValue& li = vars[i].lvalue;
|
||||
|
||||
if (li.kind == LValue::Kind_Local)
|
||||
{
|
||||
if (i < values.size)
|
||||
values.data[i]->visit(&visitor);
|
||||
|
||||
visitor.assigned[li.reg] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// and now we handle all other l-values
|
||||
for (size_t i = 0; i < vars.size(); ++i)
|
||||
{
|
||||
const LValue& li = vars[i].lvalue;
|
||||
|
||||
if (li.kind != LValue::Kind_Local && i < values.size)
|
||||
values.data[i]->visit(&visitor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// mark any registers that are used *after* assignment as conflicting
|
||||
for (size_t i = 0; i < vars.size(); ++i)
|
||||
{
|
||||
const LValue& li = vars[i].lvalue;
|
||||
|
||||
if (i < values.size)
|
||||
values.data[i]->visit(&visitor);
|
||||
|
||||
if (li.kind == LValue::Kind_Local)
|
||||
visitor.assigned[li.reg] = true;
|
||||
visitor.assigned[li.reg] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// and now we handle all other l-values
|
||||
for (size_t i = 0; i < vars.size(); ++i)
|
||||
{
|
||||
const LValue& li = vars[i].lvalue;
|
||||
|
||||
if (li.kind != LValue::Kind_Local && i < values.size)
|
||||
values.data[i]->visit(&visitor);
|
||||
}
|
||||
|
||||
// mark any registers used in trailing expressions as conflicting as well
|
||||
for (size_t i = vars.size(); i < values.size; ++i)
|
||||
values.data[i]->visit(&visitor);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static double clock_period()
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauStringFormatAnyFix, false)
|
||||
|
||||
// macro to `unsign' a character
|
||||
#define uchar(c) ((unsigned char)(c))
|
||||
|
||||
|
@ -1039,21 +1037,11 @@ static int str_format(lua_State* L)
|
|||
if (formatItemSize != 1)
|
||||
luaL_error(L, "'%%*' does not take a form");
|
||||
|
||||
if (FFlag::LuauStringFormatAnyFix)
|
||||
{
|
||||
size_t length;
|
||||
const char* string = luaL_tolstring(L, arg, &length);
|
||||
size_t length;
|
||||
const char* string = luaL_tolstring(L, arg, &length);
|
||||
|
||||
luaL_addlstring(&b, string, length, -2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t length;
|
||||
const char* string = luaL_tolstring(L, arg, &length);
|
||||
|
||||
luaL_addlstring(&b, string, length, -1);
|
||||
}
|
||||
luaL_addlstring(&b, string, length, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
continue; // skip the `luaL_addlstring' at the end
|
||||
}
|
||||
|
@ -1457,7 +1445,7 @@ static int str_pack(lua_State* L)
|
|||
const char* s = luaL_checklstring(L, arg, &len);
|
||||
luaL_argcheck(L, len <= (size_t)size, arg, "string longer than given size");
|
||||
luaL_addlstring(&b, s, len, -1); // add string
|
||||
while (len++ < (size_t)size) // pad extra space
|
||||
while (len++ < (size_t)size) // pad extra space
|
||||
luaL_addchar(&b, LUAL_PACKPADBYTE);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue