From 05d9edddb6e643f7290da46edcf9c8403c4adbae Mon Sep 17 00:00:00 2001 From: Babyhamsta Date: Sat, 30 Jul 2022 22:28:28 -0500 Subject: [PATCH] Add files via upload --- CLI/Analyze.cpp | 155 ++++--- CLI/Ast.cpp | 35 +- CLI/Coverage.cpp | 8 +- CLI/Coverage.h | 2 +- CLI/FileUtils.cpp | 26 +- CLI/FileUtils.h | 2 +- CLI/Profiler.cpp | 10 +- CLI/Profiler.h | 2 +- CLI/Repl.cpp | 291 +++++++----- CLI/Repl.h | 2 +- CLI/ReplEntry.cpp | 4 +- CLI/Web.cpp | 16 +- Common/include/lluz/Bytecode.h | 504 +++++++++++++++++++++ Common/include/lluz/Common.h | 133 ++++++ Compiler/include/lluz/BytecodeBuilder.h | 262 +++++++++++ Compiler/include/lluz/Compiler.h | 68 +++ Compiler/include/luacode.h | 4 +- Compiler/src/Builtins.cpp | 187 ++++---- Compiler/src/Builtins.h | 12 +- Compiler/src/BytecodeBuilder.cpp | 565 ++++++++++++------------ Compiler/src/Compiler.cpp | 452 +++++++++---------- Compiler/src/ConstantFolding.cpp | 66 +-- Compiler/src/ConstantFolding.h | 16 +- Compiler/src/CostModel.cpp | 38 +- Compiler/src/CostModel.h | 11 +- Compiler/src/TableShape.cpp | 10 +- Compiler/src/TableShape.h | 10 +- Compiler/src/ValueTracking.cpp | 12 +- Compiler/src/ValueTracking.h | 12 +- Compiler/src/lcode.cpp | 12 +- 30 files changed, 1906 insertions(+), 1021 deletions(-) create mode 100644 Common/include/lluz/Bytecode.h create mode 100644 Common/include/lluz/Common.h create mode 100644 Compiler/include/lluz/BytecodeBuilder.h create mode 100644 Compiler/include/lluz/Compiler.h diff --git a/CLI/Analyze.cpp b/CLI/Analyze.cpp index cd50ef00..3e1e615d 100644 --- a/CLI/Analyze.cpp +++ b/CLI/Analyze.cpp @@ -1,20 +1,19 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details -#include "Luau/ModuleResolver.h" -#include "Luau/TypeInfer.h" -#include "Luau/BuiltinDefinitions.h" -#include "Luau/Frontend.h" -#include "Luau/TypeAttach.h" -#include "Luau/Transpiler.h" +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#include "lluz/ModuleResolver.h" +#include "lluz/TypeInfer.h" +#include "lluz/BuiltinDefinitions.h" +#include "lluz/Frontend.h" +#include "lluz/TypeAttach.h" +#include "lluz/Transpiler.h" #include "FileUtils.h" -#include "Flags.h" #ifdef CALLGRIND #include #endif -LUAU_FASTFLAG(DebugLuauTimeTracing) -LUAU_FASTFLAG(LuauTypeMismatchModuleNameResolution) +lluz_FASTFLAG(DebugLluTimeTracing) +lluz_FASTFLAG(LluTypeMismatchModuleNameResolution) enum class ReportFormat { @@ -23,7 +22,7 @@ enum class ReportFormat Gnu, }; -static void report(ReportFormat format, const char* name, const Luau::Location& loc, const char* type, const char* message) +static void report(ReportFormat format, const char* name, const lluz::Location& loc, const char* type, const char* message) { switch (format) { @@ -49,41 +48,41 @@ static void report(ReportFormat format, const char* name, const Luau::Location& } } -static void reportError(const Luau::Frontend& frontend, ReportFormat format, const Luau::TypeError& error) +static void reportError(const lluz::Frontend& frontend, ReportFormat format, const lluz::TypeError& error) { std::string humanReadableName = frontend.fileResolver->getHumanReadableModuleName(error.moduleName); - if (const Luau::SyntaxError* syntaxError = Luau::get_if(&error.data)) - report(format, humanReadableName.c_str(), error.location, "SyntaxError", syntaxError->message.c_str()); - else if (FFlag::LuauTypeMismatchModuleNameResolution) - report(format, humanReadableName.c_str(), error.location, "TypeError", - Luau::toString(error, Luau::TypeErrorToStringOptions{frontend.fileResolver}).c_str()); + if (const lluz::SyntaxError* syntaxError = lluz::get_if(&error.data)) + report(format, humanReadableName.c_str(), error.location, XorStr("SyntaxError"), syntaxError->message.c_str()); + else if (FFlag::LluTypeMismatchModuleNameResolution) + report(format, humanReadableName.c_str(), error.location, XorStr("TypeError"), + lluz::toString(error, lluz::TypeErrorToStringOptions{frontend.fileResolver}).c_str()); else - report(format, humanReadableName.c_str(), error.location, "TypeError", Luau::toString(error).c_str()); + report(format, humanReadableName.c_str(), error.location, XorStr("TypeError"), lluz::toString(error).c_str()); } -static void reportWarning(ReportFormat format, const char* name, const Luau::LintWarning& warning) +static void reportWarning(ReportFormat format, const char* name, const lluz::LintWarning& warning) { - report(format, name, warning.location, Luau::LintWarning::getName(warning.code), warning.text.c_str()); + report(format, name, warning.location, lluz::LintWarning::getName(warning.code), warning.text.c_str()); } -static bool analyzeFile(Luau::Frontend& frontend, const char* name, ReportFormat format, bool annotate) +static bool analyzeFile(lluz::Frontend& frontend, const char* name, ReportFormat format, bool annotate) { - Luau::CheckResult cr; + lluz::CheckResult cr; if (frontend.isDirty(name)) cr = frontend.check(name); if (!frontend.getSourceModule(name)) { - fprintf(stderr, "Error opening %s\n", name); + fprintf(stderr, XorStr("Error opening %s\n"), name); return false; } for (auto& error : cr.errors) reportError(frontend, format, error); - Luau::LintResult lr = frontend.lint(name); + lluz::LintResult lr = frontend.lint(name); std::string humanReadableName = frontend.fileResolver->getHumanReadableModuleName(name); for (auto& error : lr.errors) @@ -93,12 +92,12 @@ static bool analyzeFile(Luau::Frontend& frontend, const char* name, ReportFormat if (annotate) { - Luau::SourceModule* sm = frontend.getSourceModule(name); - Luau::ModulePtr m = frontend.moduleResolver.getModule(name); + lluz::SourceModule* sm = frontend.getSourceModule(name); + lluz::ModulePtr m = frontend.moduleResolver.getModule(name); - Luau::attachTypeData(*sm, *m); + lluz::attachTypeData(*sm, *m); - std::string annotated = Luau::transpileWithTypes(*sm->root); + std::string annotated = lluz::transpileWithTypes(*sm->root); printf("%s", annotated.c_str()); } @@ -108,58 +107,58 @@ static bool analyzeFile(Luau::Frontend& frontend, const char* name, ReportFormat static void displayHelp(const char* argv0) { - printf("Usage: %s [--mode] [options] [file list]\n", argv0); - printf("\n"); - printf("Available modes:\n"); - printf(" omitted: typecheck and lint input files\n"); - printf(" --annotate: typecheck input files and output source with type annotations\n"); - printf("\n"); - printf("Available options:\n"); - printf(" --formatter=plain: report analysis errors in Luacheck-compatible format\n"); - printf(" --formatter=gnu: report analysis errors in GNU-compatible format\n"); - printf(" --mode=strict: default to strict mode when typechecking\n"); - printf(" --timetrace: record compiler time tracing information into trace.json\n"); + printf(XorStr("Usage: %s [--mode] [options] [file list]\n"), argv0); + printf(XorStr("\n")); + printf(XorStr("Available modes:\n")); + printf(XorStr(" omitted: typecheck and lint input files\n")); + printf(XorStr(" --annotate: typecheck input files and output source with type annotations\n")); + printf(XorStr("\n")); + printf(XorStr("Available options:\n")); + printf(XorStr(" --formatter=plain: report analysis errors in Luacheck-compatible format\n")); + printf(XorStr(" --formatter=gnu: report analysis errors in GNU-compatible format\n")); + printf(XorStr(" --mode=strict: default to strict mode when typechecking\n")); + printf(XorStr(" --timetrace: record compiler time tracing information into trace.json\n")); } static int assertionHandler(const char* expr, const char* file, int line, const char* function) { - printf("%s(%d): ASSERTION FAILED: %s\n", file, line, expr); + printf(XorStr("%s(%d): ASSERTION FAILED: %s\n"), file, line, expr); return 1; } -struct CliFileResolver : Luau::FileResolver +struct CliFileResolver : lluz::FileResolver { - std::optional readSource(const Luau::ModuleName& name) override + std::optional readSource(const lluz::ModuleName& name) override { - Luau::SourceCode::Type sourceType; + lluz::SourceCode::Type sourceType; std::optional source = std::nullopt; // If the module name is "-", then read source from stdin - if (name == "-") + if (name == XorStr("-")) { source = readStdin(); - sourceType = Luau::SourceCode::Script; + sourceType = lluz::SourceCode::Script; } else { source = readFile(name); - sourceType = Luau::SourceCode::Module; + sourceType = lluz::SourceCode::Module; } if (!source) return std::nullopt; - return Luau::SourceCode{*source, sourceType}; + return lluz::SourceCode{*source, sourceType}; } - std::optional resolveModule(const Luau::ModuleInfo* context, Luau::AstExpr* node) override + std::optional resolveModule(const lluz::ModuleInfo* context, lluz::AstExpr* node) override { - if (Luau::AstExprConstantString* expr = node->as()) + if (lluz::AstExprConstantString* expr = node->as()) { - Luau::ModuleName name = std::string(expr->value.data, expr->value.size) + ".luau"; + lluz::ModuleName name = std::string(expr->value.data, expr->value.size) + ".lluz"; if (!readFile(name)) { - // fall back to .lua if a module with .luau doesn't exist + // fall back to .lua if a module with .lluz doesn't exist name = std::string(expr->value.data, expr->value.size) + ".lua"; } @@ -169,27 +168,27 @@ struct CliFileResolver : Luau::FileResolver return std::nullopt; } - std::string getHumanReadableModuleName(const Luau::ModuleName& name) const override + std::string getHumanReadableModuleName(const lluz::ModuleName& name) const override { - if (name == "-") - return "stdin"; + if (name == XorStr("-")) + return XorStr("stdin"); return name; } }; -struct CliConfigResolver : Luau::ConfigResolver +struct CliConfigResolver : lluz::ConfigResolver { - Luau::Config defaultConfig; + lluz::Config defaultConfig; - mutable std::unordered_map configCache; + mutable std::unordered_map configCache; mutable std::vector> configErrors; - CliConfigResolver(Luau::Mode mode) + CliConfigResolver(lluz::Mode mode) { defaultConfig.mode = mode; } - const Luau::Config& getConfig(const Luau::ModuleName& name) const override + const lluz::Config& getConfig(const lluz::ModuleName& name) const override { std::optional path = getParentPath(name); if (!path) @@ -198,20 +197,20 @@ struct CliConfigResolver : Luau::ConfigResolver return readConfigRec(*path); } - const Luau::Config& readConfigRec(const std::string& path) const + const lluz::Config& readConfigRec(const std::string& path) const { auto it = configCache.find(path); if (it != configCache.end()) return it->second; std::optional parent = getParentPath(path); - Luau::Config result = parent ? readConfigRec(*parent) : defaultConfig; + lluz::Config result = parent ? readConfigRec(*parent) : defaultConfig; - std::string configPath = joinPaths(path, Luau::kConfigName); + std::string configPath = joinPaths(path, lluz::kConfigName); if (std::optional contents = readFile(configPath)) { - std::optional error = Luau::parseConfig(*contents, result); + std::optional error = lluz::parseConfig(*contents, result); if (error) configErrors.push_back({configPath, *error}); } @@ -222,18 +221,20 @@ struct CliConfigResolver : Luau::ConfigResolver int main(int argc, char** argv) { - Luau::assertHandler() = assertionHandler; + lluz::assertHandler() = assertionHandler; - setLuauFlagsDefault(); + for (lluz::FValue* flag = lluz::FValue::list; flag; flag = flag->next) + if (strncmp(flag->name, XorStr("lluz"), 4) == 0) + flag->value = true; - if (argc >= 2 && strcmp(argv[1], "--help") == 0) + if (argc >= 2 && strcmp(argv[1], XorStr("--help")) == 0) { displayHelp(argv[0]); return 0; } ReportFormat format = ReportFormat::Default; - Luau::Mode mode = Luau::Mode::Nonstrict; + lluz::Mode mode = lluz::Mode::Nonstrict; bool annotate = false; for (int i = 1; i < argc; ++i) @@ -246,32 +247,30 @@ int main(int argc, char** argv) else if (strcmp(argv[i], "--formatter=gnu") == 0) format = ReportFormat::Gnu; else if (strcmp(argv[i], "--mode=strict") == 0) - mode = Luau::Mode::Strict; + mode = lluz::Mode::Strict; else if (strcmp(argv[i], "--annotate") == 0) annotate = true; else if (strcmp(argv[i], "--timetrace") == 0) - FFlag::DebugLuauTimeTracing.value = true; - else if (strncmp(argv[i], "--fflags=", 9) == 0) - setLuauFlags(argv[i] + 9); + FFlag::DebugLluTimeTracing.value = true; } -#if !defined(LUAU_ENABLE_TIME_TRACE) - if (FFlag::DebugLuauTimeTracing) +#if !defined(lluz_ENABLE_TIME_TRACE) + if (FFlag::DebugLluTimeTracing) { - fprintf(stderr, "To run with --timetrace, Luau has to be built with LUAU_ENABLE_TIME_TRACE enabled\n"); + printf(XorStr("To run with --timetrace, lluz has to be built with lluz_ENABLE_TIME_TRACE enabled\n")); return 1; } #endif - Luau::FrontendOptions frontendOptions; + lluz::FrontendOptions frontendOptions; frontendOptions.retainFullTypeGraphs = annotate; CliFileResolver fileResolver; CliConfigResolver configResolver(mode); - Luau::Frontend frontend(&fileResolver, &configResolver, frontendOptions); + lluz::Frontend frontend(&fileResolver, &configResolver, frontendOptions); - Luau::registerBuiltinTypes(frontend.typeChecker); - Luau::freeze(frontend.typeChecker.globalTypes); + lluz::registerBuiltinTypes(frontend.typeChecker); + lluz::freeze(frontend.typeChecker.globalTypes); #ifdef CALLGRIND CALLGRIND_ZERO_STATS; diff --git a/CLI/Ast.cpp b/CLI/Ast.cpp index 6ee608c4..cc18bdb7 100644 --- a/CLI/Ast.cpp +++ b/CLI/Ast.cpp @@ -1,11 +1,11 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include -#include "Luau/Common.h" -#include "Luau/Ast.h" -#include "Luau/JsonEncoder.h" -#include "Luau/Parser.h" -#include "Luau/ParseOptions.h" +#include "lluz/Common.h" +#include "lluz/Ast.h" +#include "lluz/JsonEncoder.h" +#include "lluz/Parser.h" +#include "lluz/ParseOptions.h" #include "FileUtils.h" @@ -22,10 +22,10 @@ static int assertionHandler(const char* expr, const char* file, int line, const int main(int argc, char** argv) { - Luau::assertHandler() = assertionHandler; + lluz::assertHandler() = assertionHandler; - for (Luau::FValue* flag = Luau::FValue::list; flag; flag = flag->next) - if (strncmp(flag->name, "Luau", 4) == 0) + for (lluz::FValue* flag = lluz::FValue::list; flag; flag = flag->next) + if (strncmp(flag->name, "lluz", 4) == 0) flag->value = true; if (argc >= 2 && strcmp(argv[1], "--help") == 0) @@ -58,28 +58,27 @@ int main(int argc, char** argv) std::string source = *maybeSource; - Luau::Allocator allocator; - Luau::AstNameTable names(allocator); + lluz::Allocator allocator; + lluz::AstNameTable names(allocator); - Luau::ParseOptions options; - options.captureComments = true; + lluz::ParseOptions options; options.supportContinueStatement = true; options.allowTypeAnnotations = true; options.allowDeclarationSyntax = true; - Luau::ParseResult parseResult = Luau::Parser::parse(source.data(), source.size(), names, allocator, options); + lluz::ParseResult parseResult = lluz::Parser::parse(source.data(), source.size(), names, allocator, options); if (parseResult.errors.size() > 0) { - fprintf(stderr, "Parse errors were encountered:\n"); - for (const Luau::ParseError& error : parseResult.errors) + fprintf(stderr, XorStr("Parse errors were encountered:\n")); + for (const lluz::ParseError& error : parseResult.errors) { fprintf(stderr, " %s - %s\n", toString(error.getLocation()).c_str(), error.getMessage().c_str()); } - fprintf(stderr, "\n"); + fprintf(stderr, XorStr("\n")); } - printf("%s", Luau::toJson(parseResult.root, parseResult.commentLocations).c_str()); + printf("%s", lluz::toJson(parseResult.root).c_str()); return parseResult.errors.size() > 0 ? 1 : 0; } diff --git a/CLI/Coverage.cpp b/CLI/Coverage.cpp index a509ab89..6e03ece2 100644 --- a/CLI/Coverage.cpp +++ b/CLI/Coverage.cpp @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "Coverage.h" #include "lua.h" @@ -59,14 +59,14 @@ void coverageDump(const char* path) { lua_State* L = gCoverage.L; - FILE* f = fopen(path, "w"); + FILE* f = fopen(path, XorStr("w")); if (!f) { fprintf(stderr, "Error opening coverage %s\n", path); return; } - fprintf(f, "TN:\n"); + fprintf(f, XorStr("TN:\n")); for (int fref : gCoverage.functions) { @@ -77,7 +77,7 @@ void coverageDump(const char* path) fprintf(f, "SF:%s\n", ar.short_src); lua_getcoverage(L, -1, f, coverageCallback); - fprintf(f, "end_of_record\n"); + fprintf(f, XorStr("end_of_record\n")); lua_pop(L, 1); } diff --git a/CLI/Coverage.h b/CLI/Coverage.h index 74be4e5c..4f6dc456 100644 --- a/CLI/Coverage.h +++ b/CLI/Coverage.h @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once struct lua_State; diff --git a/CLI/FileUtils.cpp b/CLI/FileUtils.cpp index 39a14ec7..4a5d2de9 100644 --- a/CLI/FileUtils.cpp +++ b/CLI/FileUtils.cpp @@ -1,7 +1,7 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "FileUtils.h" -#include "Luau/Common.h" +#include "lluz/Common.h" #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN @@ -24,7 +24,7 @@ static std::wstring fromUtf8(const std::string& path) { size_t result = MultiByteToWideChar(CP_UTF8, 0, path.data(), int(path.size()), nullptr, 0); - LUAU_ASSERT(result); + lluz_ASSERT(result); std::wstring buf(result, L'\0'); MultiByteToWideChar(CP_UTF8, 0, path.data(), int(path.size()), &buf[0], int(buf.size())); @@ -35,7 +35,7 @@ static std::wstring fromUtf8(const std::string& path) static std::string toUtf8(const std::wstring& path) { size_t result = WideCharToMultiByte(CP_UTF8, 0, path.data(), int(path.size()), nullptr, 0, nullptr, nullptr); - LUAU_ASSERT(result); + lluz_ASSERT(result); std::string buf(result, '\0'); WideCharToMultiByte(CP_UTF8, 0, path.data(), int(path.size()), &buf[0], int(buf.size()), nullptr, nullptr); @@ -47,9 +47,9 @@ static std::string toUtf8(const std::wstring& path) std::optional readFile(const std::string& name) { #ifdef _WIN32 - FILE* file = _wfopen(fromUtf8(name).c_str(), L"rb"); + FILE* file = _wfopen(fromUtf8(name).c_str(), LXorStr("rb")); #else - FILE* file = fopen(name.c_str(), "rb"); + FILE* file = fopen(name.c_str(), XorStr("rb")); #endif if (!file) @@ -106,7 +106,7 @@ static void joinPaths(std::basic_string& str, const Ch* lhs, const Ch* rhs) #ifdef _WIN32 static bool traverseDirectoryRec(const std::wstring& path, const std::function& callback) { - std::wstring query = path + std::wstring(L"/*"); + std::wstring query = path + std::wstring(LXorStr("/*")); WIN32_FIND_DATAW data; HANDLE h = FindFirstFileW(query.c_str(), &data); @@ -232,7 +232,7 @@ std::string joinPaths(const std::string& lhs, const std::string& rhs) std::optional getParentPath(const std::string& path) { - if (path == "" || path == "." || path == "/") + if (path == XorStr("") || path == XorStr(".") || path == XorStr("/")) return std::nullopt; #ifdef _WIN32 @@ -243,20 +243,20 @@ std::optional getParentPath(const std::string& path) size_t slash = path.find_last_of("\\/", path.size() - 1); if (slash == 0) - return "/"; + return XorStr("/"); if (slash != std::string::npos) return path.substr(0, slash); - return ""; + return XorStr(""); } static std::string getExtension(const std::string& path) { - size_t dot = path.find_last_of(".\\/"); + size_t dot = path.find_last_of(XorStr(".\\/")); if (dot == std::string::npos || path[dot] != '.') - return ""; + return XorStr(""); return path.substr(dot); } @@ -277,7 +277,7 @@ std::vector getSourceFiles(int argc, char** argv) traverseDirectory(argv[i], [&](const std::string& name) { std::string ext = getExtension(name); - if (ext == ".lua" || ext == ".luau") + if (ext == XorStr(".lua") || ext == XorStr(".lluz")) files.push_back(name); }); } diff --git a/CLI/FileUtils.h b/CLI/FileUtils.h index 97471cdc..63329045 100644 --- a/CLI/FileUtils.h +++ b/CLI/FileUtils.h @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include diff --git a/CLI/Profiler.cpp b/CLI/Profiler.cpp index 30a171f0..a843c42b 100644 --- a/CLI/Profiler.cpp +++ b/CLI/Profiler.cpp @@ -1,7 +1,7 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "lua.h" -#include "Luau/DenseHash.h" +#include "lluz/DenseHash.h" #include #include @@ -24,7 +24,7 @@ struct Profiler std::string stackScratch; // statistics, updated by trigger - Luau::DenseHashMap data{""}; + lluz::DenseHashMap data{""}; uint64_t gc[16] = {}; } gProfiler; @@ -112,7 +112,7 @@ void profilerStop() void profilerDump(const char* path) { - FILE* f = fopen(path, "wb"); + FILE* f = fopen(path, XorStr("wb")); if (!f) { fprintf(stderr, "Error opening profile %s\n", path); @@ -150,6 +150,6 @@ void profilerDump(const char* path) printf(", %s %.2f%%", luaC_statename(int(i)), double(p) / double(totalgc) * 100); } - printf("\n"); + printf(XorStr("\n")); } } diff --git a/CLI/Profiler.h b/CLI/Profiler.h index 67b1acfd..0ea4e9e0 100644 --- a/CLI/Profiler.h +++ b/CLI/Profiler.h @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once struct lua_State; diff --git a/CLI/Repl.cpp b/CLI/Repl.cpp index 41360731..14a8974d 100644 --- a/CLI/Repl.cpp +++ b/CLI/Repl.cpp @@ -1,20 +1,21 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "Repl.h" #include "lua.h" #include "lualib.h" -#include "Luau/Compiler.h" -#include "Luau/BytecodeBuilder.h" -#include "Luau/Parser.h" +#include "lluz/Compiler.h" +#include "lluz/BytecodeBuilder.h" +#include "lluz/Parser.h" -#include "Coverage.h" #include "FileUtils.h" -#include "Flags.h" #include "Profiler.h" +#include "Coverage.h" #include "isocline.h" +#include "..\..\..\Security\XorString.h" + #include #ifdef _WIN32 @@ -28,7 +29,7 @@ #include -LUAU_FASTFLAG(DebugLuauTimeTracing) +lluz_FASTFLAG(DebugLluTimeTracing) enum class CliMode { @@ -53,9 +54,9 @@ struct GlobalOptions int debugLevel = 1; } globalOptions; -static Luau::CompileOptions copts() +static lluz::CompileOptions copts() { - Luau::CompileOptions result = {}; + lluz::CompileOptions result = {}; result.optimizationLevel = globalOptions.optimizationLevel; result.debugLevel = globalOptions.debugLevel; result.coverageLevel = coverageActive() ? 2 : 0; @@ -71,8 +72,8 @@ static int lua_loadstring(lua_State* L) lua_setsafeenv(L, LUA_ENVIRONINDEX, false); - std::string bytecode = Luau::compile(std::string(s, l), copts()); - if (luau_load(L, chunkname, bytecode.data(), bytecode.size(), 0) == 0) + std::string bytecode = lluz::compile(std::string(s, l), copts()); + if (lluz_load(L, chunkname, bytecode.data(), bytecode.size(), 0) == 0) return 1; lua_pushnil(L); @@ -98,23 +99,18 @@ static int lua_require(lua_State* L) // return the module from the cache lua_getfield(L, -1, name.c_str()); if (!lua_isnil(L, -1)) - { - // L stack: _MODULES result return finishrequire(L); - } - lua_pop(L, 1); - std::optional source = readFile(name + ".luau"); + std::optional source = readFile(name + XorStr(".lluz")); if (!source) { - source = readFile(name + ".lua"); // try .lua if .luau doesn't exist + source = readFile(name + XorStr(".lua")); // try .lua if .lluz doesn't exist if (!source) - luaL_argerrorL(L, 1, ("error loading " + name).c_str()); // if neither .luau nor .lua exist, we have an error + luaL_argerrorL(L, 1, ("error loading " + name).c_str()); // if neither .lluz nor .lua exist, we have an error } // module needs to run in a new thread, isolated from the rest - // note: we create ML on main thread so that it doesn't inherit environment of L lua_State* GL = lua_mainthread(L); lua_State* ML = lua_newthread(GL); lua_xmove(GL, L, 1); @@ -123,8 +119,8 @@ static int lua_require(lua_State* L) luaL_sandboxthread(ML); // now we can compile & run module on the new thread - std::string bytecode = Luau::compile(*source, copts()); - if (luau_load(ML, chunkname.c_str(), bytecode.data(), bytecode.size(), 0) == 0) + std::string bytecode = lluz::compile(*source, copts()); + if (lluz_load(ML, chunkname.c_str(), bytecode.data(), bytecode.size(), 0) == 0) { if (coverageActive()) coverageTrack(ML, -1); @@ -134,32 +130,31 @@ static int lua_require(lua_State* L) if (status == 0) { if (lua_gettop(ML) == 0) - lua_pushstring(ML, "module must return a value"); + lua_pushstring(ML, XorStr("module must return a value")); else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1)) - lua_pushstring(ML, "module must return a table or function"); + lua_pushstring(ML, XorStr("module must return a table or function")); } else if (status == LUA_YIELD) { - lua_pushstring(ML, "module can not yield"); + lua_pushstring(ML, XorStr("module can not yield")); } else if (!lua_isstring(ML, -1)) { - lua_pushstring(ML, "unknown error while running module"); + lua_pushstring(ML, XorStr("unknown error while running module")); } } - // there's now a return value on top of ML; L stack: _MODULES ML + // there's now a return value on top of ML; stack of L is MODULES thread lua_xmove(ML, L, 1); lua_pushvalue(L, -1); lua_setfield(L, -4, name.c_str()); - // L stack: _MODULES ML result return finishrequire(L); } static int lua_collectgarbage(lua_State* L) { - const char* option = luaL_optstring(L, 1, "collect"); + const char* option = luaL_optstring(L, 1, XorStr("collect")); if (strcmp(option, "collect") == 0) { @@ -174,7 +169,7 @@ static int lua_collectgarbage(lua_State* L) return 1; } - luaL_error(L, "collectgarbage must be called with 'count' or 'collect'"); + luaL_error(L, XorStr("collectgarbage must be called with 'count' or 'collect'")); } #ifdef CALLGRIND @@ -203,7 +198,7 @@ static int lua_callgrind(lua_State* L) return 0; } - luaL_error(L, "callgrind must be called with one of 'running', 'zero', 'dump'"); + luaL_error(L, XorStr("callgrind must be called with one of 'running', 'zero', 'dump'")); } #endif @@ -212,11 +207,11 @@ void setupState(lua_State* L) luaL_openlibs(L); static const luaL_Reg funcs[] = { - {"loadstring", lua_loadstring}, - {"require", lua_require}, - {"collectgarbage", lua_collectgarbage}, + {XorStr("loadstring"), lua_loadstring}, + {XorStr("require"), lua_require}, + {XorStr("collectgarbage"), lua_collectgarbage}, #ifdef CALLGRIND - {"callgrind", lua_callgrind}, + {XorStr("callgrind"), lua_callgrind}, #endif {NULL, NULL}, }; @@ -230,9 +225,9 @@ void setupState(lua_State* L) std::string runCode(lua_State* L, const std::string& source) { - std::string bytecode = Luau::compile(source, copts()); + std::string bytecode = lluz::compile(source, copts()); - if (luau_load(L, "=stdin", bytecode.data(), bytecode.size(), 0) != 0) + if (lluz_load(L, XorStr("=stdin"), bytecode.data(), bytecode.size(), 0) != 0) { size_t len; const char* msg = lua_tolstring(L, -1, &len); @@ -257,13 +252,13 @@ std::string runCode(lua_State* L, const std::string& source) if (n) { - luaL_checkstack(T, LUA_MINSTACK, "too many results to print"); - lua_getglobal(T, "_PRETTYPRINT"); + luaL_checkstack(T, LUA_MINSTACK, XorStr("too many results to print")); + lua_getglobal(T, XorStr("_PRETTYPRINT")); // If _PRETTYPRINT is nil, then use the standard print function instead if (lua_isnil(T, -1)) { lua_pop(T, 1); - lua_getglobal(T, "print"); + lua_getglobal(T, XorStr("print")); } lua_insert(T, 1); lua_pcall(T, n, 0, 0); @@ -275,14 +270,14 @@ std::string runCode(lua_State* L, const std::string& source) if (status == LUA_YIELD) { - error = "thread yielded unexpectedly"; + error = XorStr("thread yielded unexpectedly"); } else if (const char* str = lua_tostring(T, -1)) { error = str; } - error += "\nstack backtrace:\n"; + error += XorStr("\nstack backtrace:\n"); error += lua_debugtrace(T); fprintf(stdout, "%s", error.c_str()); @@ -296,7 +291,7 @@ std::string runCode(lua_State* L, const std::string& source) // if it exists. Returns true iff __index exists. static bool tryReplaceTopWithIndex(lua_State* L) { - if (luaL_getmetafield(L, -1, "__index")) + if (luaL_getmetafield(L, -1, XorStr("__index"))) { // Remove the table leaving __index on the top of stack lua_remove(L, -2); @@ -326,7 +321,7 @@ static void safeGetTable(lua_State* L, int tableIndex) else { lua_pop(L, 1); // Pop the nil result - if (!luaL_getmetafield(L, -1, "__index")) + if (!luaL_getmetafield(L, -1, XorStr("__index"))) { lua_pushnil(L); break; @@ -371,7 +366,7 @@ static void completePartialMatches(lua_State* L, bool completeOnlyFunctions, con // If the last separator was a ':' (i.e. a method call) then only functions should be completed. bool requiredValueType = (!completeOnlyFunctions || valueType == LUA_TFUNCTION); - if (!key.empty() && requiredValueType && Luau::startsWith(key, prefix)) + if (!key.empty() && requiredValueType && lluz::startsWith(key, prefix)) { std::string completedComponent(key.substr(prefix.size())); std::string completion(editBuffer + completedComponent); @@ -404,7 +399,7 @@ static void completeIndexer(lua_State* L, const std::string& editBuffer, const A for (;;) { - size_t sep = lookup.find_first_of(".:"); + size_t sep = lookup.find_first_of(XorStr(".:")); std::string_view prefix = lookup.substr(0, sep); if (sep == std::string_view::npos) @@ -464,11 +459,11 @@ static void loadHistory(const char* name) { std::string path; - if (const char* home = getenv("HOME")) + if (const char* home = getenv(XorStr("HOME"))) { path = joinPaths(home, name); } - else if (const char* userProfile = getenv("USERPROFILE")) + else if (const char* userProfile = getenv(XorStr("USERPROFILE"))) { path = joinPaths(userProfile, name); } @@ -482,16 +477,16 @@ static void runReplImpl(lua_State* L) ic_set_default_completer(completeRepl, L); // Reset the locale to C - setlocale(LC_ALL, "C"); + setlocale(LC_ALL, XorStr("C")); // Make brace matching easier to see - ic_style_def("ic-bracematch", "teal"); + ic_style_def(XorStr("ic-bracematch"), XorStr("teal")); // Prevent auto insertion of braces ic_enable_brace_insertion(false); // Loads history from the given file; isocline automatically saves the history on process exit - loadHistory(".luau_history"); + loadHistory(XorStr(".lluz_history")); std::string buffer; @@ -502,7 +497,7 @@ static void runReplImpl(lua_State* L) if (!line) break; - if (buffer.empty() && runCode(L, std::string("return ") + line.get()) == std::string()) + if (buffer.empty() && runCode(L, std::string(XorStr("return ")) + line.get()) == std::string()) { ic_history_add(line.get()); continue; @@ -514,7 +509,7 @@ static void runReplImpl(lua_State* L) std::string error = runCode(L, buffer); - if (error.length() >= 5 && error.compare(error.length() - 5, 5, "") == 0) + if (error.length() >= 5 && error.compare(error.length() - 5, 5, XorStr("")) == 0) { continue; } @@ -545,7 +540,7 @@ static bool runFile(const char* name, lua_State* GL, bool repl) std::optional source = readFile(name); if (!source) { - fprintf(stderr, "Error opening %s\n", name); + fprintf(stderr, XorStr("Error opening %s\n"), name); return false; } @@ -557,10 +552,10 @@ static bool runFile(const char* name, lua_State* GL, bool repl) std::string chunkname = "=" + std::string(name); - std::string bytecode = Luau::compile(*source, copts()); + std::string bytecode = lluz::compile(*source, copts()); int status = 0; - if (luau_load(L, chunkname.c_str(), bytecode.data(), bytecode.size(), 0) == 0) + if (lluz_load(L, chunkname.c_str(), bytecode.data(), bytecode.size(), 0) == 0) { if (coverageActive()) coverageTrack(L, -1); @@ -578,14 +573,14 @@ static bool runFile(const char* name, lua_State* GL, bool repl) if (status == LUA_YIELD) { - error = "thread yielded unexpectedly"; + error = XorStr("thread yielded unexpectedly"); } else if (const char* str = lua_tostring(L, -1)) { error = str; } - error += "\nstacktrace:\n"; + error += XorStr("\nstacktrace:\n"); error += lua_debugtrace(L); fprintf(stderr, "%s", error.c_str()); @@ -599,19 +594,19 @@ static bool runFile(const char* name, lua_State* GL, bool repl) return status == 0; } -static void report(const char* name, const Luau::Location& location, const char* type, const char* message) +static void report(const char* name, const lluz::Location& location, const char* type, const char* message) { - fprintf(stderr, "%s(%d,%d): %s: %s\n", name, location.begin.line + 1, location.begin.column + 1, type, message); + fprintf(stderr, XorStr("%s(%d,%d): %s: %s\n"), name, location.begin.line + 1, location.begin.column + 1, type, message); } -static void reportError(const char* name, const Luau::ParseError& error) +static void reportError(const char* name, const lluz::ParseError& error) { - report(name, error.getLocation(), "SyntaxError", error.what()); + report(name, error.getLocation(), XorStr("SyntaxError"), error.what()); } -static void reportError(const char* name, const Luau::CompileError& error) +static void reportError(const char* name, const lluz::CompileError& error) { - report(name, error.getLocation(), "CompileError", error.what()); + report(name, error.getLocation(), XorStr("CompileError"), error.what()); } static bool compileFile(const char* name, CompileFormat format) @@ -619,22 +614,22 @@ static bool compileFile(const char* name, CompileFormat format) std::optional source = readFile(name); if (!source) { - fprintf(stderr, "Error opening %s\n", name); + fprintf(stderr, XorStr("Error opening %s\n"), name); return false; } try { - Luau::BytecodeBuilder bcb; + lluz::BytecodeBuilder bcb; if (format == CompileFormat::Text) { - bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code | Luau::BytecodeBuilder::Dump_Source | Luau::BytecodeBuilder::Dump_Locals | - Luau::BytecodeBuilder::Dump_Remarks); + bcb.setDumpFlags(lluz::BytecodeBuilder::Dump_Code | lluz::BytecodeBuilder::Dump_Source | lluz::BytecodeBuilder::Dump_Locals | + lluz::BytecodeBuilder::Dump_Remarks); bcb.setDumpSource(*source); } - Luau::compileOrThrow(bcb, *source, copts()); + lluz::compileOrThrow(bcb, *source, copts()); switch (format) { @@ -650,13 +645,13 @@ static bool compileFile(const char* name, CompileFormat format) return true; } - catch (Luau::ParseErrors& e) + catch (lluz::ParseErrors& e) { for (auto& error : e.getErrors()) reportError(name, error); return false; } - catch (Luau::CompileError& e) + catch (lluz::CompileError& e) { reportError(name, e); return false; @@ -665,35 +660,84 @@ static bool compileFile(const char* name, CompileFormat format) static void displayHelp(const char* argv0) { - printf("Usage: %s [--mode] [options] [file list]\n", argv0); - printf("\n"); - printf("When mode and file list are omitted, an interactive REPL is started instead.\n"); - printf("\n"); - printf("Available modes:\n"); - printf(" omitted: compile and run input files one by one\n"); - printf(" --compile[=format]: compile input files and output resulting formatted bytecode (binary or text)\n"); - printf("\n"); - printf("Available options:\n"); - printf(" --coverage: collect code coverage while running the code and output results to coverage.out\n"); - printf(" -h, --help: Display this usage message.\n"); - printf(" -i, --interactive: Run an interactive REPL after executing the last script specified.\n"); - printf(" -O: compile with optimization level n (default 1, n should be between 0 and 2).\n"); - printf(" -g: compile with debug level n (default 1, n should be between 0 and 2).\n"); - printf(" --profile[=N]: profile the code using N Hz sampling (default 10000) and output results to profile.out\n"); - printf(" --timetrace: record compiler time tracing information into trace.json\n"); + printf(XorStr("Usage: %s [--mode] [options] [file list]\n"), argv0); + printf(XorStr("\n")); + printf(XorStr("When mode and file list are omitted, an interactive REPL is started instead.\n")); + printf(XorStr("\n")); + printf(XorStr("Available modes:\n")); + printf(XorStr(" omitted: compile and run input files one by one\n")); + printf(XorStr(" --compile[=format]: compile input files and output resulting formatted bytecode (binary or text)\n")); + printf(XorStr("\n")); + printf(XorStr("Available options:\n")); + printf(XorStr(" --coverage: collect code coverage while running the code and output results to coverage.out\n")); + printf(XorStr(" -h, --help: Display this usage message.\n")); + printf(XorStr(" -i, --interactive: Run an interactive REPL after executing the last script specified.\n")); + printf(XorStr(" -O: compile with optimization level n (default 1, n should be between 0 and 2).\n")); + printf(XorStr(" -g: compile with debug level n (default 1, n should be between 0 and 2).\n")); + printf(XorStr(" --profile[=N]: profile the code using N Hz sampling (default 10000) and output results to profile.out\n")); + printf(XorStr(" --timetrace: record compiler time tracing information into trace.json\n")); } static int assertionHandler(const char* expr, const char* file, int line, const char* function) { - printf("%s(%d): ASSERTION FAILED: %s\n", file, line, expr); + printf(XorStr("%s(%d): ASSERTION FAILED: %s\n"), file, line, expr); return 1; } +static void setlluzFlags(bool state) +{ + for (lluz::FValue* flag = lluz::FValue::list; flag; flag = flag->next) + { + if (strncmp(flag->name, XorStr("lluz"), 4) == 0) + flag->value = state; + } +} + +static void setFlag(std::string_view name, bool state) +{ + for (lluz::FValue* flag = lluz::FValue::list; flag; flag = flag->next) + { + if (name == flag->name) + { + flag->value = state; + return; + } + } + + fprintf(stderr, XorStr("Warning: --fflag unrecognized flag '%.*s'.\n\n"), int(name.length()), name.data()); +} + +static void applyFlagKeyValue(std::string_view element) +{ + if (size_t separator = element.find('='); separator != std::string_view::npos) + { + std::string_view key = element.substr(0, separator); + std::string_view value = element.substr(separator + 1); + + if (value == XorStr("true")) + setFlag(key, true); + else if (value == XorStr("false")) + setFlag(key, false); + else + fprintf(stderr, XorStr("Warning: --fflag unrecognized value '%.*s' for flag '%.*s'.\n\n"), int(value.length()), value.data(), int(key.length()), + key.data()); + } + else + { + if (element == XorStr("true")) + setlluzFlags(true); + else if (element == XorStr("false")) + setlluzFlags(false); + else + setFlag(element, true); + } +} + int replMain(int argc, char** argv) { - Luau::assertHandler() = assertionHandler; + lluz::assertHandler() = assertionHandler; - setLuauFlagsDefault(); + setlluzFlags(true); CliMode mode = CliMode::Unknown; CompileFormat compileFormat{}; @@ -703,50 +747,50 @@ int replMain(int argc, char** argv) // Set the mode if the user has explicitly specified one. int argStart = 1; - if (argc >= 2 && strncmp(argv[1], "--compile", strlen("--compile")) == 0) + if (argc >= 2 && strncmp(argv[1], XorStr("--compile"), strlen(XorStr("--compile"))) == 0) { argStart++; mode = CliMode::Compile; - if (strcmp(argv[1], "--compile") == 0) + if (strcmp(argv[1], XorStr("--compile")) == 0) { compileFormat = CompileFormat::Text; } - else if (strcmp(argv[1], "--compile=binary") == 0) + else if (strcmp(argv[1], XorStr("--compile=binary")) == 0) { compileFormat = CompileFormat::Binary; } - else if (strcmp(argv[1], "--compile=text") == 0) + else if (strcmp(argv[1], XorStr("--compile=text")) == 0) { compileFormat = CompileFormat::Text; } - else if (strcmp(argv[1], "--compile=null") == 0) + else if (strcmp(argv[1], XorStr("--compile=null")) == 0) { compileFormat = CompileFormat::Null; } else { - fprintf(stderr, "Error: Unrecognized value for '--compile' specified.\n"); + fprintf(stderr, XorStr("Error: Unrecognized value for '--compile' specified.\n")); return 1; } } for (int i = argStart; i < argc; i++) { - if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) + if (strcmp(argv[i], XorStr("-h")) == 0 || strcmp(argv[i], XorStr("--help")) == 0) { displayHelp(argv[0]); return 0; } - else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--interactive") == 0) + else if (strcmp(argv[i], XorStr("-i")) == 0 || strcmp(argv[i], XorStr("--interactive")) == 0) { interactive = true; } - else if (strncmp(argv[i], "-O", 2) == 0) + else if (strncmp(argv[i], XorStr("-O"), 2) == 0) { int level = atoi(argv[i] + 2); if (level < 0 || level > 2) { - fprintf(stderr, "Error: Optimization level must be between 0 and 2 inclusive.\n"); + fprintf(stderr, XorStr("Error: Optimization level must be between 0 and 2 inclusive.\n")); return 1; } globalOptions.optimizationLevel = level; @@ -756,47 +800,56 @@ int replMain(int argc, char** argv) int level = atoi(argv[i] + 2); if (level < 0 || level > 2) { - fprintf(stderr, "Error: Debug level must be between 0 and 2 inclusive.\n"); + fprintf(stderr, XorStr("Error: Debug level must be between 0 and 2 inclusive.\n")); return 1; } globalOptions.debugLevel = level; } - else if (strcmp(argv[i], "--profile") == 0) + else if (strcmp(argv[i], XorStr("--profile")) == 0) { profile = 10000; // default to 10 KHz } - else if (strncmp(argv[i], "--profile=", 10) == 0) + else if (strncmp(argv[i], XorStr("--profile="), 10) == 0) { profile = atoi(argv[i] + 10); } - else if (strcmp(argv[i], "--coverage") == 0) + else if (strcmp(argv[i], XorStr("--coverage")) == 0) { coverage = true; } - else if (strcmp(argv[i], "--timetrace") == 0) + else if (strcmp(argv[i], XorStr("--timetrace")) == 0) { - FFlag::DebugLuauTimeTracing.value = true; + FFlag::DebugLluTimeTracing.value = true; + +#if !defined(lluz_ENABLE_TIME_TRACE) + printf(XorStr("To run with --timetrace, lluz has to be built with lluz_ENABLE_TIME_TRACE enabled\n")); + return 1; +#endif } - else if (strncmp(argv[i], "--fflags=", 9) == 0) + else if (strncmp(argv[i], XorStr("--fflags="), 9) == 0) { - setLuauFlags(argv[i] + 9); + std::string_view list = argv[i] + 9; + + while (!list.empty()) + { + size_t ending = list.find(XorStr(",")); + + applyFlagKeyValue(list.substr(0, ending)); + + if (ending != std::string_view::npos) + list.remove_prefix(ending + 1); + else + break; + } } else if (argv[i][0] == '-') { - fprintf(stderr, "Error: Unrecognized option '%s'.\n\n", argv[i]); + fprintf(stderr, XorStr("Error: Unrecognized option '%s'.\n\n"), argv[i]); displayHelp(argv[0]); return 1; } } -#if !defined(LUAU_ENABLE_TIME_TRACE) - if (FFlag::DebugLuauTimeTracing) - { - fprintf(stderr, "To run with --timetrace, Luau has to be built with LUAU_ENABLE_TIME_TRACE enabled\n"); - return 1; - } -#endif - const std::vector files = getSourceFiles(argc, argv); if (mode == CliMode::Unknown) { @@ -848,17 +901,17 @@ int replMain(int argc, char** argv) if (profile) { profilerStop(); - profilerDump("profile.out"); + profilerDump(XorStr("profile.out")); } if (coverage) - coverageDump("coverage.out"); + coverageDump(XorStr("coverage.out")); return failed ? 1 : 0; } case CliMode::Unknown: default: - LUAU_ASSERT(!"Unhandled cli mode."); + lluz_ASSERT(!XorStr("Unhandled cli mode.")); return 1; } } diff --git a/CLI/Repl.h b/CLI/Repl.h index cd54b7e0..a310b6df 100644 --- a/CLI/Repl.h +++ b/CLI/Repl.h @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "lua.h" diff --git a/CLI/ReplEntry.cpp b/CLI/ReplEntry.cpp index 8543e3f7..edadad6e 100644 --- a/CLI/ReplEntry.cpp +++ b/CLI/ReplEntry.cpp @@ -1,6 +1,8 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "Repl.h" + + int main(int argc, char** argv) { return replMain(argc, argv); diff --git a/CLI/Web.cpp b/CLI/Web.cpp index 416a79f2..3286cf1e 100644 --- a/CLI/Web.cpp +++ b/CLI/Web.cpp @@ -1,9 +1,9 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "lua.h" #include "lualib.h" #include "luacode.h" -#include "Luau/Common.h" +#include "lluz/Common.h" #include @@ -19,8 +19,8 @@ static void setupState(lua_State* L) static std::string runCode(lua_State* L, const std::string& source) { size_t bytecodeSize = 0; - char* bytecode = luau_compile(source.data(), source.length(), nullptr, &bytecodeSize); - int result = luau_load(L, "=stdin", bytecode, bytecodeSize, 0); + char* bytecode = lluz_compile(source.data(), source.length(), nullptr, &bytecodeSize); + int result = lluz_load(L, "=stdin", bytecode, bytecodeSize, 0); free(bytecode); if (result != 0) @@ -48,8 +48,8 @@ static std::string runCode(lua_State* L, const std::string& source) if (n) { - luaL_checkstack(T, LUA_MINSTACK, "too many results to print"); - lua_getglobal(T, "print"); + luaL_checkstack(T, LUA_MINSTACK, XorStr("too many results to print")); + lua_getglobal(T, XorStr("print")); lua_insert(T, 1); lua_pcall(T, n, 0, 0); } @@ -90,8 +90,8 @@ static std::string runCode(lua_State* L, const std::string& source) extern "C" const char* executeScript(const char* source) { // setup flags - for (Luau::FValue* flag = Luau::FValue::list; flag; flag = flag->next) - if (strncmp(flag->name, "Luau", 4) == 0) + for (lluz::FValue* flag = lluz::FValue::list; flag; flag = flag->next) + if (strncmp(flag->name, "lluz", 4) == 0) flag->value = true; // create new state diff --git a/Common/include/lluz/Bytecode.h b/Common/include/lluz/Bytecode.h new file mode 100644 index 00000000..ee0a0c63 --- /dev/null +++ b/Common/include/lluz/Bytecode.h @@ -0,0 +1,504 @@ +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#pragma once + +// clang-format off + +// This header contains the bytecode definition for lluz interpreter +// Creating the bytecode is outside the scope of this file and is handled by bytecode builder (BytecodeBuilder.h) and bytecode compiler (Compiler.h) +// Note that ALL enums declared in this file are order-sensitive since the values are baked into bytecode that needs to be processed by legacy clients. + +// # Bytecode definitions +// Bytecode instructions are using "word code" - each instruction is one or many 32-bit words. +// The first word in the instruction is always the instruction header, and *must* contain the opcode (enum below) in the least significant byte. +// +// Instruction word can be encoded using one of the following encodings: +// ABC - least-significant byte for the opcode, followed by three bytes, A, B and C; each byte declares a register index, small index into some other table or an unsigned integral value +// AD - least-significant byte for the opcode, followed by A byte, followed by D half-word (16-bit integer). D is a signed integer that commonly specifies constant table index or jump offset +// E - least-significant byte for the opcode, followed by E (24-bit integer). E is a signed integer that commonly specifies a jump offset +// +// Instruction word is sometimes followed by one extra word, indicated as AUX - this is just a 32-bit word and is decoded according to the specification for each opcode. +// For each opcode the encoding is *static* - that is, based on the opcode you know a-priory how large the instruction is, with the exception of NEWCLOSURE + +// # Bytecode indices +// Bytecode instructions commonly refer to integer values that define offsets or indices for various entities. For each type, there's a maximum encodable value. +// Note that in some cases, the compiler will set a lower limit than the maximum encodable value is to prevent fragile code into bumping against the limits whenever we change the compilation details. +// Additionally, in some specific instructions such as ANDK, the limit on the encoded value is smaller; this means that if a value is larger, a different instruction must be selected. +// +// Registers: 0-254. Registers refer to the values on the function's stack frame, including arguments. +// 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. + +// # 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 +// range (indicated by LBC_BYTECODE_MIN / LBC_BYTECODE_MAX) and was produced by lluz compiler, it should load and execute correctly. +// +// Note that lluz runtime doesn't provide indefinite bytecode compatibility: support for older versions gets removed over time. As such, bytecode isn't a durable storage format and it's expected +// that lluz users can recompile bytecode from source on lluz version upgrades if necessary. + +// Bytecode opcode, part of the instruction header +enum lluzOpcode +{ + // NOP: noop + LOP_NOP, + + // BREAK: debugger break + LOP_BREAK, + + // LOADNIL: sets register to nil + // A: target register + LOP_LOADNIL, + + // LOADB: sets register to boolean and jumps to a given short offset (used to compile comparison results into a boolean) + // A: target register + // B: value (0/1) + // C: jump offset + LOP_LOADB, + + // LOADN: sets register to a number literal + // A: target register + // D: value (-32768..32767) + LOP_LOADN, + + // LOADK: sets register to an entry from the constant table from the proto (number/string) + // A: target register + // D: constant table index (0..32767) + LOP_LOADK, + + // MOVE: move (copy) value from one register to another + // A: target register + // B: source register + LOP_MOVE, + + // GETGLOBAL: load value from global table using constant string as a key + // A: target register + // C: predicted slot index (based on hash) + // AUX: constant table index + LOP_GETGLOBAL, + + // SETGLOBAL: set value in global table using constant string as a key + // A: source register + // C: predicted slot index (based on hash) + // AUX: constant table index + LOP_SETGLOBAL, + + // GETUPVAL: load upvalue from the upvalue table for the current function + // A: target register + // B: upvalue index (0..255) + LOP_GETUPVAL, + + // SETUPVAL: store value into the upvalue table for the current function + // A: target register + // B: upvalue index (0..255) + LOP_SETUPVAL, + + // CLOSEUPVALS: close (migrate to heap) all upvalues that were captured for registers >= target + // A: target register + LOP_CLOSEUPVALS, + + // GETIMPORT: load imported global table global from the constant table + // A: target register + // D: constant table index (0..32767); we assume that imports are loaded into the constant table + // AUX: 3 10-bit indices of constant strings that, combined, constitute an import path; length of the path is set by the top 2 bits (1,2,3) + LOP_GETIMPORT, + + // GETTABLE: load value from table into target register using key from register + // A: target register + // B: table register + // C: index register + LOP_GETTABLE, + + // SETTABLE: store source register into table using key from register + // A: source register + // B: table register + // C: index register + LOP_SETTABLE, + + // GETTABLEKS: load value from table into target register using constant string as a key + // A: target register + // B: table register + // C: predicted slot index (based on hash) + // AUX: constant table index + LOP_GETTABLEKS, + + // SETTABLEKS: store source register into table using constant string as a key + // A: source register + // B: table register + // C: predicted slot index (based on hash) + // AUX: constant table index + LOP_SETTABLEKS, + + // GETTABLEN: load value from table into target register using small integer index as a key + // A: target register + // B: table register + // C: index-1 (index is 1..256) + LOP_GETTABLEN, + + // SETTABLEN: store source register into table using small integer index as a key + // A: source register + // B: table register + // C: index-1 (index is 1..256) + LOP_SETTABLEN, + + // NEWCLOSURE: create closure from a child proto; followed by a CAPTURE instruction for each upvalue + // A: target register + // D: child proto index (0..32767) + LOP_NEWCLOSURE, + + // NAMECALL: prepare to call specified method by name by loading function from source register using constant index into target register and copying source register into target register + 1 + // A: target register + // B: source register + // C: predicted slot index (based on hash) + // AUX: constant table index + // Note that this instruction must be followed directly by CALL; it prepares the arguments + // This instruction is roughly equivalent to GETTABLEKS + MOVE pair, but we need a special instruction to support custom __namecall metamethod + LOP_NAMECALL, + + // CALL: call specified function + // A: register where the function object lives, followed by arguments; results are placed starting from the same register + // B: argument count + 1, or 0 to preserve all arguments up to top (MULTRET) + // C: result count + 1, or 0 to preserve all values and adjust top (MULTRET) + LOP_CALL, + + // RETURN: returns specified values from the function + // A: register where the returned values start + // B: number of returned values + 1, or 0 to return all values up to top (MULTRET) + LOP_RETURN, + + // JUMP: jumps to target offset + // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") + LOP_JUMP, + + // JUMPBACK: jumps to target offset; this is equivalent to JUMP but is used as a safepoint to be able to interrupt while/repeat loops + // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") + LOP_JUMPBACK, + + // JUMPIF: jumps to target offset if register is not nil/false + // A: source register + // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") + LOP_JUMPIF, + + // JUMPIFNOT: jumps to target offset if register is nil/false + // A: source register + // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") + LOP_JUMPIFNOT, + + // 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") + // AUX: source register 2 + LOP_JUMPIFEQ, + LOP_JUMPIFLE, + LOP_JUMPIFLT, + LOP_JUMPIFNOTEQ, + LOP_JUMPIFNOTLE, + LOP_JUMPIFNOTLT, + + // ADD, SUB, MUL, DIV, MOD, POW: compute arithmetic operation between two source registers and put the result into target register + // A: target register + // B: source register 1 + // C: source register 2 + LOP_ADD, + LOP_SUB, + LOP_MUL, + LOP_DIV, + LOP_MOD, + LOP_POW, + + // ADDK, SUBK, MULK, DIVK, MODK, POWK: compute arithmetic operation between the source register and a constant and put the result into target register + // A: target register + // B: source register + // C: constant table index (0..255) + LOP_ADDK, + LOP_SUBK, + LOP_MULK, + LOP_DIVK, + LOP_MODK, + LOP_POWK, + + // AND, OR: perform `and` or `or` operation (selecting first or second register based on whether the first one is truthy) and put the result into target register + // A: target register + // B: source register 1 + // C: source register 2 + LOP_AND, + LOP_OR, + + // ANDK, ORK: perform `and` or `or` operation (selecting source register or constant based on whether the source register is truthy) and put the result into target register + // A: target register + // B: source register + // C: constant table index (0..255) + LOP_ANDK, + LOP_ORK, + + // CONCAT: concatenate all strings between B and C (inclusive) and put the result into A + // A: target register + // B: source register start + // C: source register end + LOP_CONCAT, + + // NOT, MINUS, LENGTH: compute unary operation for source register and put the result into target register + // A: target register + // B: source register + LOP_NOT, + LOP_MINUS, + LOP_LENGTH, + + // NEWTABLE: create table in target register + // A: target register + // B: table size, stored as 0 for v=0 and ceil(log2(v))+1 for v!=0 + // AUX: array size + LOP_NEWTABLE, + + // DUPTABLE: duplicate table using the constant table template to target register + // A: target register + // D: constant table index (0..32767) + LOP_DUPTABLE, + + // SETLIST: set a list of values to table in target register + // A: target register + // B: source register start + // C: value count + 1, or 0 to use all values up to top (MULTRET) + // AUX: table index to start from + LOP_SETLIST, + + // FORNPREP: prepare a numeric for loop, jump over the loop if first iteration doesn't need to run + // A: target register; numeric for loops assume a register layout [limit, step, index, variable] + // D: jump offset (-32768..32767) + // limit/step are immutable, index isn't visible to user code since it's copied into variable + LOP_FORNPREP, + + // FORNLOOP: adjust loop variables for one iteration, jump back to the loop header if loop needs to continue + // A: target register; see FORNPREP for register layout + // D: jump offset (-32768..32767) + LOP_FORNLOOP, + + // FORGLOOP: adjust loop variables for one iteration of a generic for loop, jump back to the loop header if loop needs to continue + // A: target register; generic for loops assume a register layout [generator, state, index, variables...] + // D: jump offset (-32768..32767) + // AUX: variable count (1..255) in the low 8 bits, high bit indicates whether to use ipairs-style traversal in the fast path + // loop variables are adjusted by calling generator(state, index) and expecting it to return a tuple that's copied to the user variables + // the first variable is then copied into index; generator/state are immutable, index isn't visible to user code + LOP_FORGLOOP, + + // FORGPREP_INEXT/FORGLOOP_INEXT: FORGLOOP with 2 output variables (no AUX encoding), assuming generator is luaB_inext + // FORGPREP_INEXT prepares the index variable and jumps to FORGLOOP_INEXT + // FORGLOOP_INEXT has identical encoding and semantics to FORGLOOP (except for AUX encoding) + LOP_FORGPREP_INEXT, + LOP_FORGLOOP_INEXT, + + // FORGPREP_NEXT/FORGLOOP_NEXT: FORGLOOP with 2 output variables (no AUX encoding), assuming generator is luaB_next + // FORGPREP_NEXT prepares the index variable and jumps to FORGLOOP_NEXT + // FORGLOOP_NEXT has identical encoding and semantics to FORGLOOP (except for AUX encoding) + LOP_FORGPREP_NEXT, + LOP_FORGLOOP_NEXT, + + // GETVARARGS: copy variables into the target register from vararg storage for current function + // A: target register + // B: variable count + 1, or 0 to copy all variables and adjust top (MULTRET) + LOP_GETVARARGS, + + // DUPCLOSURE: create closure from a pre-created function object (reusing it unless environments diverge) + // A: target register + // D: constant table index (0..32767) + LOP_DUPCLOSURE, + + // PREPVARARGS: prepare stack for variadic functions so that GETVARARGS works correctly + // A: number of fixed arguments + LOP_PREPVARARGS, + + // LOADKX: sets register to an entry from the constant table from the proto (number/string) + // A: target register + // AUX: constant table index + LOP_LOADKX, + + // JUMPX: jumps to the target offset; like JUMPBACK, supports interruption + // E: jump offset (-2^23..2^23; 0 means "next instruction" aka "don't jump") + LOP_JUMPX, + + // FASTCALL: perform a fast call of a built-in function + // A: builtin function id (see lluzBuiltinFunction) + // C: jump offset to get to following CALL + // FASTCALL is followed by one of (GETIMPORT, MOVE, GETUPVAL) instructions and by CALL instruction + // This is necessary so that if FASTCALL can't perform the call inline, it can continue normal execution + // If FASTCALL *can* perform the call, it jumps over the instructions *and* over the next CALL + // Note that FASTCALL will read the actual call arguments, such as argument/result registers and counts, from the CALL instruction + LOP_FASTCALL, + + // COVERAGE: update coverage information stored in the instruction + // E: hit count for the instruction (0..2^23-1) + // The hit count is incremented by VM every time the instruction is executed, and saturates at 2^23-1 + LOP_COVERAGE, + + // CAPTURE: capture a local or an upvalue as an upvalue into a newly created closure; only valid after NEWCLOSURE + // A: capture type, see lluzCaptureType + // B: source register (for VAL/REF) or upvalue index (for UPVAL/UPREF) + LOP_CAPTURE, + + // JUMPIFEQK, JUMPIFNOTEQK: jumps to target offset if the comparison with constant is true (or false, for NOT variants) + // A: source register 1 + // D: jump offset (-32768..32767; 0 means "next instruction" aka "don't jump") + // AUX: constant table index + LOP_JUMPIFEQK, + LOP_JUMPIFNOTEQK, + + // FASTCALL1: perform a fast call of a built-in function using 1 register argument + // A: builtin function id (see lluzBuiltinFunction) + // B: source argument register + // C: jump offset to get to following CALL + LOP_FASTCALL1, + + // FASTCALL2: perform a fast call of a built-in function using 2 register arguments + // A: builtin function id (see lluzBuiltinFunction) + // B: source argument register + // C: jump offset to get to following CALL + // AUX: source register 2 in least-significant byte + LOP_FASTCALL2, + + // FASTCALL2K: perform a fast call of a built-in function using 1 register argument and 1 constant argument + // A: builtin function id (see lluzBuiltinFunction) + // B: source argument register + // C: jump offset to get to following CALL + // AUX: constant index + LOP_FASTCALL2K, + + // FORGPREP: prepare loop variables for a generic for loop, jump to the loop backedge unconditionally + // A: target register; generic for loops assume a register layout [generator, state, index, variables...] + // D: jump offset (-32768..32767) + LOP_FORGPREP, + + // Enum entry for number of opcodes, not a valid opcode by itself! + LOP__COUNT +}; + +// Bytecode instruction header: it's always a 32-bit integer, with low byte (first byte in little endian) containing the opcode +// Some instruction types require more data and have more 32-bit integers following the header +#define lluz_INSN_OP(insn) ((insn) & 0xff) + +// ABC encoding: three 8-bit values, containing registers or small numbers +#define lluz_INSN_A(insn) (((insn) >> 8) & 0xff) +#define lluz_INSN_B(insn) (((insn) >> 16) & 0xff) +#define lluz_INSN_C(insn) (((insn) >> 24) & 0xff) + +// AD encoding: one 8-bit value, one signed 16-bit value +#define lluz_INSN_D(insn) (int32_t(insn) >> 16) + +// E encoding: one signed 24-bit value +#define lluz_INSN_E(insn) (int32_t(insn) >> 8) + +// Bytecode tags, used internally for bytecode encoded as a string +enum lluzBytecodeTag +{ + // Bytecode version; runtime supports [MIN, MAX], compiler emits TARGET by default but may emit a higher version when flags are enabled + LBC_VERSION_MIN = 2, + LBC_VERSION_MAX = 2, + LBC_VERSION_TARGET = 2, + // Types of constant table entries + LBC_CONSTANT_NIL = 0, + LBC_CONSTANT_BOOLEAN, + LBC_CONSTANT_NUMBER, + LBC_CONSTANT_STRING, + LBC_CONSTANT_IMPORT, + LBC_CONSTANT_TABLE, + LBC_CONSTANT_CLOSURE, +}; + +// Builtin function ids, used in LOP_FASTCALL +enum lluzBuiltinFunction +{ + LBF_NONE = 0, + + // assert() + LBF_ASSERT, + + // math. + LBF_MATH_ABS, + LBF_MATH_ACOS, + LBF_MATH_ASIN, + LBF_MATH_ATAN2, + LBF_MATH_ATAN, + LBF_MATH_CEIL, + LBF_MATH_COSH, + LBF_MATH_COS, + LBF_MATH_DEG, + LBF_MATH_EXP, + LBF_MATH_FLOOR, + LBF_MATH_FMOD, + LBF_MATH_FREXP, + LBF_MATH_LDEXP, + LBF_MATH_LOG10, + LBF_MATH_LOG, + LBF_MATH_MAX, + LBF_MATH_MIN, + LBF_MATH_MODF, + LBF_MATH_POW, + LBF_MATH_RAD, + LBF_MATH_SINH, + LBF_MATH_SIN, + LBF_MATH_SQRT, + LBF_MATH_TANH, + LBF_MATH_TAN, + + // bit32. + LBF_BIT32_ARSHIFT, + LBF_BIT32_BAND, + LBF_BIT32_BNOT, + LBF_BIT32_BOR, + LBF_BIT32_BXOR, + LBF_BIT32_BTEST, + LBF_BIT32_EXTRACT, + LBF_BIT32_LROTATE, + LBF_BIT32_LSHIFT, + LBF_BIT32_REPLACE, + LBF_BIT32_RROTATE, + LBF_BIT32_RSHIFT, + + // type() + LBF_TYPE, + + // string. + LBF_STRING_BYTE, + LBF_STRING_CHAR, + LBF_STRING_LEN, + + // typeof() + LBF_TYPEOF, + + // string. + LBF_STRING_SUB, + + // math. + LBF_MATH_CLAMP, + LBF_MATH_SIGN, + LBF_MATH_ROUND, + + // raw* + LBF_RAWSET, + LBF_RAWGET, + LBF_RAWEQUAL, + + // table. + LBF_TABLE_INSERT, + LBF_TABLE_UNPACK, + + // vector ctor + LBF_VECTOR, + + // bit32.count + LBF_BIT32_COUNTLZ, + LBF_BIT32_COUNTRZ, + + // select(_, ...) + LBF_SELECT_VARARG, + + // rawlen + LBF_RAWLEN, +}; + +// Capture type, used in LOP_CAPTURE +enum lluzCaptureType +{ + LCT_VAL = 0, + LCT_REF, + LCT_UPVAL, +}; diff --git a/Common/include/lluz/Common.h b/Common/include/lluz/Common.h new file mode 100644 index 00000000..2004133f --- /dev/null +++ b/Common/include/lluz/Common.h @@ -0,0 +1,133 @@ +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#pragma once + +// Compiler codegen control macros +#ifdef _MSC_VER +#define lluz_NORETURN __declspec(noreturn) +#define lluz_NOINLINE __declspec(noinline) +#define lluz_FORCEINLINE __forceinline +#define lluz_LIKELY(x) x +#define lluz_UNLIKELY(x) x +#define lluz_UNREACHABLE() __assume(false) +#define lluz_DEBUGBREAK() __debugbreak() +#else +#define lluz_NORETURN __attribute__((__noreturn__)) +#define lluz_NOINLINE __attribute__((noinline)) +#define lluz_FORCEINLINE inline __attribute__((always_inline)) +#define lluz_LIKELY(x) __builtin_expect(x, 1) +#define lluz_UNLIKELY(x) __builtin_expect(x, 0) +#define lluz_UNREACHABLE() __builtin_unreachable() +#define lluz_DEBUGBREAK() __builtin_trap() +#endif + + + + + + + +namespace lluz +{ + +using AssertHandler = int (*)(const char* expression, const char* file, int line, const char* function); + +inline AssertHandler& assertHandler() +{ + static AssertHandler handler = nullptr; + return handler; +} + +inline int assertCallHandler(const char* expression, const char* file, int line, const char* function) +{ + if (AssertHandler handler = assertHandler()) + return handler(expression, file, line, function); + + return 1; +} + +} // namespace lluz + +#if !defined(NDEBUG) || defined(lluz_ENABLE_ASSERT) +#define lluz_ASSERT(expr) ((void)(!!(expr) || (lluz::assertCallHandler(#expr, __FILE__, __LINE__, __FUNCTION__) && (lluz_DEBUGBREAK(), 0)))) +#define lluz_ASSERTENABLED +#else +#define lluz_ASSERT(expr) (void)sizeof(!!(expr)) +#endif + +namespace lluz +{ + +template +struct FValue +{ + static FValue* list; + + T value; + bool dynamic; + const char* name; + FValue* next; + + FValue(const char* name, T def, bool dynamic, void (*reg)(const char*, T*, bool) = nullptr) + : value(def) + , dynamic(dynamic) + , name(name) + , next(list) + { + list = this; + + if (reg) + reg(name, &value, dynamic); + } + + operator T() const + { + return value; + } +}; + +template +FValue* FValue::list = nullptr; + +} // namespace lluz + +#define lluz_FASTFLAG(flag) \ + namespace FFlag \ + { \ + extern lluz::FValue flag; \ + } +#define lluz_FASTFLAGVARIABLE(flag, def) \ + namespace FFlag \ + { \ + lluz::FValue flag(#flag, def, false, nullptr); \ + } +#define lluz_FASTINT(flag) \ + namespace FInt \ + { \ + extern lluz::FValue flag; \ + } +#define lluz_FASTINTVARIABLE(flag, def) \ + namespace FInt \ + { \ + lluz::FValue flag(#flag, def, false, nullptr); \ + } + +#define lluz_DYNAMIC_FASTFLAG(flag) \ + namespace DFFlag \ + { \ + extern lluz::FValue flag; \ + } +#define lluz_DYNAMIC_FASTFLAGVARIABLE(flag, def) \ + namespace DFFlag \ + { \ + lluz::FValue flag(#flag, def, true, nullptr); \ + } +#define lluz_DYNAMIC_FASTINT(flag) \ + namespace DFInt \ + { \ + extern lluz::FValue flag; \ + } +#define lluz_DYNAMIC_FASTINTVARIABLE(flag, def) \ + namespace DFInt \ + { \ + lluz::FValue flag(#flag, def, true, nullptr); \ + } diff --git a/Compiler/include/lluz/BytecodeBuilder.h b/Compiler/include/lluz/BytecodeBuilder.h new file mode 100644 index 00000000..6d2f6d28 --- /dev/null +++ b/Compiler/include/lluz/BytecodeBuilder.h @@ -0,0 +1,262 @@ +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#pragma once + +#include "lluz/Bytecode.h" +#include "lluz/DenseHash.h" +#include "lluz/StringUtils.h" + +#include + +namespace lluz +{ + +class BytecodeEncoder +{ +public: + virtual ~BytecodeEncoder() {} + + virtual uint8_t encodeOp(uint8_t op) = 0; +}; + +class BytecodeBuilder +{ +public: + // BytecodeBuilder does *not* copy the data passed via StringRef; instead, it keeps the ref around until finalize() + // Please be careful with the lifetime of the data that's being passed because of this. + // The safe and correct pattern is to only build StringRefs out of pieces of AST (AstName or AstArray<>) that are backed by AstAllocator. + // Note that you must finalize() the builder before the Allocator backing the Ast is destroyed. + struct StringRef + { + // To construct a StringRef, use sref() from Compiler.cpp. + const char* data = nullptr; + size_t length = 0; + + bool operator==(const StringRef& other) const; + }; + + struct TableShape + { + static const unsigned int kMaxLength = 32; + + int32_t keys[kMaxLength]; + unsigned int length = 0; + + bool operator==(const TableShape& other) const; + }; + + BytecodeBuilder(BytecodeEncoder* encoder = 0); + + uint32_t beginFunction(uint8_t numparams, bool isvararg = false); + void endFunction(uint8_t maxstacksize, uint8_t numupvalues); + + void setMainFunction(uint32_t fid); + + int32_t addConstantNil(); + int32_t addConstantBoolean(bool value); + int32_t addConstantNumber(double value); + int32_t addConstantString(StringRef value); + int32_t addImport(uint32_t iid); + int32_t addConstantTable(const TableShape& shape); + int32_t addConstantClosure(uint32_t fid); + + int16_t addChildFunction(uint32_t fid); + + void emitABC(lluzOpcode op, uint8_t a, uint8_t b, uint8_t c); + void emitAD(lluzOpcode op, uint8_t a, int16_t d); + void emitE(lluzOpcode op, int32_t e); + void emitAux(uint32_t aux); + + size_t emitLabel(); + + [[nodiscard]] bool patchJumpD(size_t jumpLabel, size_t targetLabel); + [[nodiscard]] bool patchSkipC(size_t jumpLabel, size_t targetLabel); + + void foldJumps(); + void expandJumps(); + + void setDebugFunctionName(StringRef name); + void setDebugFunctionLineDefined(int line); + void setDebugLine(int line); + void pushDebugLocal(StringRef name, uint8_t reg, uint32_t startpc, uint32_t endpc); + void pushDebugUpval(StringRef name); + uint32_t getDebugPC() const; + + void addDebugRemark(const char* format, ...) lluz_PRINTF_ATTR(2, 3); + + void finalize(); + + enum DumpFlags + { + Dump_Code = 1 << 0, + Dump_Lines = 1 << 1, + Dump_Source = 1 << 2, + Dump_Locals = 1 << 3, + Dump_Remarks = 1 << 4, + }; + + void setDumpFlags(uint32_t flags) + { + dumpFlags = flags; + dumpFunctionPtr = &BytecodeBuilder::dumpCurrentFunction; + } + + void setDumpSource(const std::string& source); + + const std::string& getBytecode() const + { + lluz_ASSERT(!bytecode.empty()); // did you forget to call finalize? + return bytecode; + } + + std::string dumpFunction(uint32_t id) const; + std::string dumpEverything() const; + + static uint32_t getImportId(int32_t id0); + static uint32_t getImportId(int32_t id0, int32_t id1); + static uint32_t getImportId(int32_t id0, int32_t id1, int32_t id2); + + static uint32_t getStringHash(StringRef key); + + static std::string getError(const std::string& message); + + static uint8_t getVersion(); + +private: + struct Constant + { + enum Type + { + Type_Nil, + Type_Boolean, + Type_Number, + Type_String, + Type_Import, + Type_Table, + Type_Closure, + }; + + Type type; + union + { + bool valueBoolean; + double valueNumber; + unsigned int valueString; // index into string table + uint32_t valueImport; // 10-10-10-2 encoded import id + uint32_t valueTable; // index into tableShapes[] + uint32_t valueClosure; // index of function in global list + }; + }; + + struct ConstantKey + { + Constant::Type type; + // Note: this stores value* from Constant; when type is Number_Double, this stores the same bits as double does but in uint64_t. + uint64_t value; + + bool operator==(const ConstantKey& key) const + { + return type == key.type && value == key.value; + } + }; + + struct Function + { + std::string data; + + uint8_t maxstacksize = 0; + uint8_t numparams = 0; + uint8_t numupvalues = 0; + bool isvararg = false; + + unsigned int debugname = 0; + int debuglinedefined = 0; + + std::string dump; + std::string dumpname; + }; + + struct DebugLocal + { + unsigned int name; + + uint8_t reg; + uint32_t startpc; + uint32_t endpc; + }; + + struct DebugUpval + { + unsigned int name; + }; + + struct Jump + { + uint32_t source; + uint32_t target; + }; + + struct StringRefHash + { + size_t operator()(const StringRef& v) const; + }; + + struct ConstantKeyHash + { + size_t operator()(const ConstantKey& key) const; + }; + + struct TableShapeHash + { + size_t operator()(const TableShape& v) const; + }; + + std::vector functions; + uint32_t currentFunction = ~0u; + uint32_t mainFunction = ~0u; + + std::vector insns; + std::vector lines; + std::vector constants; + std::vector protos; + std::vector jumps; + + std::vector tableShapes; + + bool hasLongJumps = false; + + DenseHashMap constantMap; + DenseHashMap tableShapeMap; + DenseHashMap protoMap; + + int debugLine = 0; + + std::vector debugLocals; + std::vector debugUpvals; + + DenseHashMap stringTable; + + std::vector> debugRemarks; + std::string debugRemarkBuffer; + + BytecodeEncoder* encoder = nullptr; + std::string bytecode; + + uint32_t dumpFlags = 0; + std::vector dumpSource; + + std::string (BytecodeBuilder::*dumpFunctionPtr)() const = nullptr; + + void validate() const; + + std::string dumpCurrentFunction() const; + void dumpInstruction(const uint32_t* opcode, std::string& output, int targetLabel) const; + + void writeFunction(std::string& ss, uint32_t id) const; + void writeLineInfo(std::string& ss) const; + void writeStringTable(std::string& ss) const; + + int32_t addConstant(const ConstantKey& key, const Constant& value); + unsigned int addStringTableEntry(StringRef value); +}; + +} // namespace lluz diff --git a/Compiler/include/lluz/Compiler.h b/Compiler/include/lluz/Compiler.h new file mode 100644 index 00000000..b3050d0f --- /dev/null +++ b/Compiler/include/lluz/Compiler.h @@ -0,0 +1,68 @@ +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#pragma once + +#include "lluz/ParseOptions.h" +#include "lluz/Location.h" +#include "lluz/StringUtils.h" +#include "lluz/Common.h" + +namespace lluz +{ +class AstStatBlock; +class AstNameTable; +class BytecodeBuilder; +class BytecodeEncoder; + +// Note: this structure is duplicated in luacode.h, don't forget to change these in sync! +struct CompileOptions +{ + // 0 - no optimization + // 1 - baseline optimization level that doesn't prevent debuggability + // 2 - includes optimizations that harm debuggability such as inlining + int optimizationLevel = 1; + + // 0 - no debugging support + // 1 - line info & function names only; sufficient for backtraces + // 2 - full debug info with local & upvalue names; necessary for debugger + int debugLevel = 1; + + // 0 - no code coverage support + // 1 - statement coverage + // 2 - statement and expression coverage (verbose) + int coverageLevel = 0; + + // global builtin to construct vectors; disabled by default + const char* vectorLib = nullptr; + const char* vectorCtor = nullptr; + + // null-terminated array of globals that are mutable; disables the import optimization for fields accessed through these + const char** mutableGlobals = nullptr; +}; + +class CompileError : public std::exception +{ +public: + CompileError(const Location& location, const std::string& message); + + virtual ~CompileError() throw(); + + virtual const char* what() const throw(); + + const Location& getLocation() const; + + static lluz_NORETURN void raise(const Location& location, const char* format, ...) lluz_PRINTF_ATTR(2, 3); + +private: + Location location; + std::string message; +}; + +// compiles bytecode into bytecode builder using either a pre-parsed AST or parsing it from source; throws on errors +void compileOrThrow(BytecodeBuilder& bytecode, AstStatBlock* root, const AstNameTable& names, const CompileOptions& options = {}); +void compileOrThrow(BytecodeBuilder& bytecode, const std::string& source, const CompileOptions& options = {}, const ParseOptions& parseOptions = {}); + +// compiles bytecode into a bytecode blob, that either contains the valid bytecode or an encoded error that lluz_load can decode +std::string compile( + const std::string& source, const CompileOptions& options = {}, const ParseOptions& parseOptions = {}, BytecodeEncoder* encoder = nullptr); + +} // namespace lluz diff --git a/Compiler/include/luacode.h b/Compiler/include/luacode.h index e235a2e7..5b624241 100644 --- a/Compiler/include/luacode.h +++ b/Compiler/include/luacode.h @@ -1,4 +1,4 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include @@ -36,4 +36,4 @@ struct lua_CompileOptions }; /* compile source to bytecode; when source compilation fails, the resulting bytecode contains the encoded error. use free() to destroy */ -LUACODE_API char* luau_compile(const char* source, size_t size, lua_CompileOptions* options, size_t* outsize); +LUACODE_API char* lluz_compile(const char* source, size_t size, lua_CompileOptions* options, size_t* outsize); diff --git a/Compiler/src/Builtins.cpp b/Compiler/src/Builtins.cpp index 3650c147..9be42d05 100644 --- a/Compiler/src/Builtins.cpp +++ b/Compiler/src/Builtins.cpp @@ -1,12 +1,14 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "Builtins.h" -#include "Luau/Bytecode.h" -#include "Luau/Compiler.h" +#include "lluz/Bytecode.h" +#include "lluz/Compiler.h" -LUAU_FASTFLAGVARIABLE(LuauCompileRawlen, false) +#include "..\..\..\..\Security\XorString.h" -namespace Luau +lluz_FASTFLAGVARIABLE(LluCompileRawlen, false) + +namespace lluz { namespace Compile { @@ -40,143 +42,146 @@ Builtin getBuiltin(AstExpr* node, const DenseHashMap& globals, } } -static int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& options) +int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& options) { - if (builtin.isGlobal("assert")) + if (builtin.empty()) + return -1; + + if (builtin.isGlobal(XorStr("assert"))) return LBF_ASSERT; - if (builtin.isGlobal("type")) + if (builtin.isGlobal(XorStr("type"))) return LBF_TYPE; - if (builtin.isGlobal("typeof")) + if (builtin.isGlobal(XorStr("typeof"))) return LBF_TYPEOF; - if (builtin.isGlobal("rawset")) + if (builtin.isGlobal(XorStr("rawset"))) return LBF_RAWSET; - if (builtin.isGlobal("rawget")) + if (builtin.isGlobal(XorStr("rawget"))) return LBF_RAWGET; - if (builtin.isGlobal("rawequal")) + if (builtin.isGlobal(XorStr("rawequal"))) return LBF_RAWEQUAL; - if (FFlag::LuauCompileRawlen && builtin.isGlobal("rawlen")) + if (FFlag::LluCompileRawlen && builtin.isGlobal(XorStr("rawlen"))) return LBF_RAWLEN; - if (builtin.isGlobal("unpack")) + if (builtin.isGlobal(XorStr("unpack"))) return LBF_TABLE_UNPACK; - if (builtin.isGlobal("select")) + if (builtin.isGlobal(XorStr("select"))) return LBF_SELECT_VARARG; - if (builtin.object == "math") + if (builtin.object == XorStr("math")) { - if (builtin.method == "abs") + if (builtin.method == XorStr("abs")) return LBF_MATH_ABS; - if (builtin.method == "acos") + if (builtin.method == XorStr("acos")) return LBF_MATH_ACOS; - if (builtin.method == "asin") + if (builtin.method == XorStr("asin")) return LBF_MATH_ASIN; - if (builtin.method == "atan2") + if (builtin.method == XorStr("atan2")) return LBF_MATH_ATAN2; - if (builtin.method == "atan") + if (builtin.method == XorStr("atan")) return LBF_MATH_ATAN; - if (builtin.method == "ceil") + if (builtin.method == XorStr("ceil")) return LBF_MATH_CEIL; - if (builtin.method == "cosh") + if (builtin.method == XorStr("cosh")) return LBF_MATH_COSH; - if (builtin.method == "cos") + if (builtin.method == XorStr("cos")) return LBF_MATH_COS; - if (builtin.method == "deg") + if (builtin.method == XorStr("deg")) return LBF_MATH_DEG; - if (builtin.method == "exp") + if (builtin.method == XorStr("exp")) return LBF_MATH_EXP; - if (builtin.method == "floor") + if (builtin.method == XorStr("floor")) return LBF_MATH_FLOOR; - if (builtin.method == "fmod") + if (builtin.method == XorStr("fmod")) return LBF_MATH_FMOD; - if (builtin.method == "frexp") + if (builtin.method == XorStr("frexp")) return LBF_MATH_FREXP; - if (builtin.method == "ldexp") + if (builtin.method == XorStr("ldexp")) return LBF_MATH_LDEXP; - if (builtin.method == "log10") + if (builtin.method == XorStr("log10")) return LBF_MATH_LOG10; - if (builtin.method == "log") + if (builtin.method == XorStr("log")) return LBF_MATH_LOG; - if (builtin.method == "max") + if (builtin.method == XorStr("max")) return LBF_MATH_MAX; - if (builtin.method == "min") + if (builtin.method == XorStr("min")) return LBF_MATH_MIN; - if (builtin.method == "modf") + if (builtin.method == XorStr("modf")) return LBF_MATH_MODF; - if (builtin.method == "pow") + if (builtin.method == XorStr("pow")) return LBF_MATH_POW; - if (builtin.method == "rad") + if (builtin.method == XorStr("rad")) return LBF_MATH_RAD; - if (builtin.method == "sinh") + if (builtin.method == XorStr("sinh")) return LBF_MATH_SINH; - if (builtin.method == "sin") + if (builtin.method == XorStr("sin")) return LBF_MATH_SIN; - if (builtin.method == "sqrt") + if (builtin.method == XorStr("sqrt")) return LBF_MATH_SQRT; - if (builtin.method == "tanh") + if (builtin.method == XorStr("tanh")) return LBF_MATH_TANH; - if (builtin.method == "tan") + if (builtin.method == XorStr("tan")) return LBF_MATH_TAN; - if (builtin.method == "clamp") + if (builtin.method == XorStr("clamp")) return LBF_MATH_CLAMP; - if (builtin.method == "sign") + if (builtin.method == XorStr("sign")) return LBF_MATH_SIGN; - if (builtin.method == "round") + if (builtin.method == XorStr("round")) return LBF_MATH_ROUND; } - if (builtin.object == "bit32") + if (builtin.object == XorStr("bit32")) { - if (builtin.method == "arshift") + if (builtin.method == XorStr("arshift")) return LBF_BIT32_ARSHIFT; - if (builtin.method == "band") + if (builtin.method == XorStr("band")) return LBF_BIT32_BAND; - if (builtin.method == "bnot") + if (builtin.method == XorStr("bnot")) return LBF_BIT32_BNOT; - if (builtin.method == "bor") + if (builtin.method == XorStr("bor")) return LBF_BIT32_BOR; - if (builtin.method == "bxor") + if (builtin.method == XorStr("bxor")) return LBF_BIT32_BXOR; - if (builtin.method == "btest") + if (builtin.method == XorStr("btest")) return LBF_BIT32_BTEST; - if (builtin.method == "extract") + if (builtin.method == XorStr("extract")) return LBF_BIT32_EXTRACT; - if (builtin.method == "lrotate") + if (builtin.method == XorStr("lrotate")) return LBF_BIT32_LROTATE; - if (builtin.method == "lshift") + if (builtin.method == XorStr("lshift")) return LBF_BIT32_LSHIFT; - if (builtin.method == "replace") + if (builtin.method == XorStr("replace")) return LBF_BIT32_REPLACE; - if (builtin.method == "rrotate") + if (builtin.method == XorStr("rrotate")) return LBF_BIT32_RROTATE; - if (builtin.method == "rshift") + if (builtin.method == XorStr("rshift")) return LBF_BIT32_RSHIFT; - if (builtin.method == "countlz") + if (builtin.method == XorStr("countlz")) return LBF_BIT32_COUNTLZ; - if (builtin.method == "countrz") + if (builtin.method == XorStr("countrz")) return LBF_BIT32_COUNTRZ; } - if (builtin.object == "string") + if (builtin.object == XorStr("string")) { - if (builtin.method == "byte") + if (builtin.method == XorStr("byte")) return LBF_STRING_BYTE; - if (builtin.method == "char") + if (builtin.method == XorStr("char")) return LBF_STRING_CHAR; - if (builtin.method == "len") + if (builtin.method == XorStr("len")) return LBF_STRING_LEN; - if (builtin.method == "sub") + if (builtin.method == XorStr("sub")) return LBF_STRING_SUB; } - if (builtin.object == "table") + if (builtin.object == XorStr("table")) { - if (builtin.method == "insert") + if (builtin.method == XorStr("insert")) return LBF_TABLE_INSERT; - if (builtin.method == "unpack") + if (builtin.method == XorStr("unpack")) return LBF_TABLE_UNPACK; } @@ -197,49 +202,5 @@ static int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& op return -1; } -struct BuiltinVisitor : AstVisitor -{ - DenseHashMap& result; - - const DenseHashMap& globals; - const DenseHashMap& variables; - - const CompileOptions& options; - - BuiltinVisitor(DenseHashMap& result, const DenseHashMap& globals, - const DenseHashMap& variables, const CompileOptions& options) - : result(result) - , globals(globals) - , variables(variables) - , options(options) - { - } - - bool visit(AstExprCall* node) override - { - Builtin builtin = node->self ? Builtin() : getBuiltin(node->func, globals, variables); - if (builtin.empty()) - return true; - - int bfid = getBuiltinFunctionId(builtin, options); - - // getBuiltinFunctionId optimistically assumes all select() calls are builtin but actually the second argument must be a vararg - if (bfid == LBF_SELECT_VARARG && !(node->args.size == 2 && node->args.data[1]->is())) - bfid = -1; - - if (bfid >= 0) - result[node] = bfid; - - return true; // propagate to nested calls - } -}; - -void analyzeBuiltins(DenseHashMap& result, const DenseHashMap& globals, - const DenseHashMap& variables, const CompileOptions& options, AstNode* root) -{ - BuiltinVisitor visitor{result, globals, variables, options}; - root->visit(&visitor); -} - } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/Builtins.h b/Compiler/src/Builtins.h index 4399c532..96a4f064 100644 --- a/Compiler/src/Builtins.h +++ b/Compiler/src/Builtins.h @@ -1,14 +1,14 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "ValueTracking.h" -namespace Luau +namespace lluz { struct CompileOptions; } -namespace Luau +namespace lluz { namespace Compile { @@ -35,9 +35,7 @@ struct Builtin }; Builtin getBuiltin(AstExpr* node, const DenseHashMap& globals, const DenseHashMap& variables); - -void analyzeBuiltins(DenseHashMap& result, const DenseHashMap& globals, - const DenseHashMap& variables, const CompileOptions& options, AstNode* root); +int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& options); } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/BytecodeBuilder.cpp b/Compiler/src/BytecodeBuilder.cpp index 64327bd0..d0d5cf25 100644 --- a/Compiler/src/BytecodeBuilder.cpp +++ b/Compiler/src/BytecodeBuilder.cpp @@ -1,12 +1,14 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details -#include "Luau/BytecodeBuilder.h" +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#include "lluz/BytecodeBuilder.h" -#include "Luau/StringUtils.h" +#include "lluz/StringUtils.h" + +#include "..\..\..\..\Security\XorString.h" #include #include -namespace Luau +namespace lluz { static_assert(LBC_VERSION_TARGET >= LBC_VERSION_MIN && LBC_VERSION_TARGET <= LBC_VERSION_MAX, "Invalid bytecode version setup"); @@ -19,7 +21,7 @@ static const int kMaxJumpDistance = 1 << 23; static int log2(int v) { - LUAU_ASSERT(v); + lluz_ASSERT(v); int r = 0; @@ -53,7 +55,7 @@ static void writeVarInt(std::string& ss, unsigned int value) } while (value); } -static int getOpLength(LuauOpcode op) +static int getOpLength(lluzOpcode op) { switch (op) { @@ -84,7 +86,7 @@ static int getOpLength(LuauOpcode op) } } -inline bool isJumpD(LuauOpcode op) +inline bool isJumpD(lluzOpcode op) { switch (op) { @@ -115,22 +117,11 @@ inline bool isJumpD(LuauOpcode op) } } -inline bool isSkipC(LuauOpcode op) +inline bool isSkipC(lluzOpcode op) { switch (op) { case LOP_LOADB: - return true; - - default: - return false; - } -} - -inline bool isFastCall(LuauOpcode op) -{ - switch (op) - { case LOP_FASTCALL: case LOP_FASTCALL1: case LOP_FASTCALL2: @@ -144,16 +135,14 @@ inline bool isFastCall(LuauOpcode op) static int getJumpTarget(uint32_t insn, uint32_t pc) { - LuauOpcode op = LuauOpcode(LUAU_INSN_OP(insn)); + lluzOpcode op = lluzOpcode(lluz_INSN_OP(insn)); if (isJumpD(op)) - return int(pc + LUAU_INSN_D(insn) + 1); - else if (isFastCall(op)) - return int(pc + LUAU_INSN_C(insn) + 2); - else if (isSkipC(op) && LUAU_INSN_C(insn)) - return int(pc + LUAU_INSN_C(insn) + 1); + return int(pc + lluz_INSN_D(insn) + 1); + else if (isSkipC(op) && lluz_INSN_C(insn)) + return int(pc + lluz_INSN_C(insn) + 1); else if (op == LOP_JUMPX) - return int(pc + LUAU_INSN_E(insn) + 1); + return int(pc + lluz_INSN_E(insn) + 1); else return -1; } @@ -215,7 +204,7 @@ BytecodeBuilder::BytecodeBuilder(BytecodeEncoder* encoder) , stringTable({nullptr, 0}) , encoder(encoder) { - LUAU_ASSERT(stringTable.find(StringRef{"", 0}) == nullptr); + lluz_ASSERT(stringTable.find(StringRef{"", 0}) == nullptr); // preallocate some buffers that are very likely to grow anyway; this works around std::vector's inefficient growth policy for small arrays insns.reserve(32); @@ -227,7 +216,7 @@ BytecodeBuilder::BytecodeBuilder(BytecodeEncoder* encoder) uint32_t BytecodeBuilder::beginFunction(uint8_t numparams, bool isvararg) { - LUAU_ASSERT(currentFunction == ~0u); + lluz_ASSERT(currentFunction == ~0u); uint32_t id = uint32_t(functions.size()); @@ -247,14 +236,14 @@ uint32_t BytecodeBuilder::beginFunction(uint8_t numparams, bool isvararg) void BytecodeBuilder::endFunction(uint8_t maxstacksize, uint8_t numupvalues) { - LUAU_ASSERT(currentFunction != ~0u); + lluz_ASSERT(currentFunction != ~0u); Function& func = functions[currentFunction]; func.maxstacksize = maxstacksize; func.numupvalues = numupvalues; -#ifdef LUAU_ASSERTENABLED +#ifdef lluz_ASSERTENABLED validate(); #endif @@ -289,7 +278,7 @@ void BytecodeBuilder::endFunction(uint8_t maxstacksize, uint8_t numupvalues) void BytecodeBuilder::setMainFunction(uint32_t fid) { - LUAU_ASSERT(fid < functions.size()); + lluz_ASSERT(fid < functions.size()); mainFunction = fid; } @@ -418,7 +407,7 @@ int16_t BytecodeBuilder::addChildFunction(uint32_t fid) return int16_t(id); } -void BytecodeBuilder::emitABC(LuauOpcode op, uint8_t a, uint8_t b, uint8_t c) +void BytecodeBuilder::emitABC(lluzOpcode op, uint8_t a, uint8_t b, uint8_t c) { uint32_t insn = uint32_t(op) | (a << 8) | (b << 16) | (c << 24); @@ -426,7 +415,7 @@ void BytecodeBuilder::emitABC(LuauOpcode op, uint8_t a, uint8_t b, uint8_t c) lines.push_back(debugLine); } -void BytecodeBuilder::emitAD(LuauOpcode op, uint8_t a, int16_t d) +void BytecodeBuilder::emitAD(lluzOpcode op, uint8_t a, int16_t d) { uint32_t insn = uint32_t(op) | (a << 8) | (uint16_t(d) << 16); @@ -434,7 +423,7 @@ void BytecodeBuilder::emitAD(LuauOpcode op, uint8_t a, int16_t d) lines.push_back(debugLine); } -void BytecodeBuilder::emitE(LuauOpcode op, int32_t e) +void BytecodeBuilder::emitE(lluzOpcode op, int32_t e) { uint32_t insn = uint32_t(op) | (uint32_t(e) << 8); @@ -455,15 +444,15 @@ size_t BytecodeBuilder::emitLabel() bool BytecodeBuilder::patchJumpD(size_t jumpLabel, size_t targetLabel) { - LUAU_ASSERT(jumpLabel < insns.size()); + lluz_ASSERT(jumpLabel < insns.size()); unsigned int jumpInsn = insns[jumpLabel]; (void)jumpInsn; - LUAU_ASSERT(isJumpD(LuauOpcode(LUAU_INSN_OP(jumpInsn)))); - LUAU_ASSERT(LUAU_INSN_D(jumpInsn) == 0); + lluz_ASSERT(isJumpD(lluzOpcode(lluz_INSN_OP(jumpInsn)))); + lluz_ASSERT(lluz_INSN_D(jumpInsn) == 0); - LUAU_ASSERT(targetLabel <= insns.size()); + lluz_ASSERT(targetLabel <= insns.size()); int offset = int(targetLabel) - int(jumpLabel) - 1; @@ -487,13 +476,13 @@ bool BytecodeBuilder::patchJumpD(size_t jumpLabel, size_t targetLabel) bool BytecodeBuilder::patchSkipC(size_t jumpLabel, size_t targetLabel) { - LUAU_ASSERT(jumpLabel < insns.size()); + lluz_ASSERT(jumpLabel < insns.size()); unsigned int jumpInsn = insns[jumpLabel]; (void)jumpInsn; - LUAU_ASSERT(isSkipC(LuauOpcode(LUAU_INSN_OP(jumpInsn))) || isFastCall(LuauOpcode(LUAU_INSN_OP(jumpInsn)))); - LUAU_ASSERT(LUAU_INSN_C(jumpInsn) == 0); + lluz_ASSERT(isSkipC(lluzOpcode(lluz_INSN_OP(jumpInsn)))); + lluz_ASSERT(lluz_INSN_C(jumpInsn) == 0); int offset = int(targetLabel) - int(jumpLabel) - 1; @@ -574,7 +563,7 @@ void BytecodeBuilder::addDebugRemark(const char* format, ...) void BytecodeBuilder::finalize() { - LUAU_ASSERT(bytecode.empty()); + lluz_ASSERT(bytecode.empty()); // preallocate space for bytecode blob size_t capacity = 16; @@ -589,7 +578,7 @@ void BytecodeBuilder::finalize() // assemble final bytecode blob uint8_t version = getVersion(); - LUAU_ASSERT(version >= LBC_VERSION_MIN && version <= LBC_VERSION_MAX); + lluz_ASSERT(version >= LBC_VERSION_MIN && version <= LBC_VERSION_MAX); bytecode = char(version); @@ -600,13 +589,13 @@ void BytecodeBuilder::finalize() for (const Function& func : functions) bytecode += func.data; - LUAU_ASSERT(mainFunction < functions.size()); + lluz_ASSERT(mainFunction < functions.size()); writeVarInt(bytecode, mainFunction); } void BytecodeBuilder::writeFunction(std::string& ss, uint32_t id) const { - LUAU_ASSERT(id < functions.size()); + lluz_ASSERT(id < functions.size()); const Function& func = functions[id]; // header @@ -620,10 +609,10 @@ void BytecodeBuilder::writeFunction(std::string& ss, uint32_t id) const for (size_t i = 0; i < insns.size();) { - uint8_t op = LUAU_INSN_OP(insns[i]); - LUAU_ASSERT(op < LOP__COUNT); + uint8_t op = lluz_INSN_OP(insns[i]); + lluz_ASSERT(op < LOP__COUNT); - int oplen = getOpLength(LuauOpcode(op)); + int oplen = getOpLength(lluzOpcode(op)); uint8_t openc = encoder ? encoder->encodeOp(op) : op; writeInt(ss, openc | (insns[i] & ~0xff)); @@ -681,7 +670,7 @@ void BytecodeBuilder::writeFunction(std::string& ss, uint32_t id) const break; default: - LUAU_ASSERT(!"Unsupported constant type"); + lluz_ASSERT(!"Unsupported constant type"); } } @@ -746,7 +735,7 @@ void BytecodeBuilder::writeFunction(std::string& ss, uint32_t id) const void BytecodeBuilder::writeLineInfo(std::string& ss) const { - LUAU_ASSERT(!lines.empty()); + lluz_ASSERT(!lines.empty()); // this function encodes lines inside each span as a 8-bit delta to span baseline // span is always a power of two; depending on the line info input, it may need to be as low as 1 @@ -812,7 +801,7 @@ void BytecodeBuilder::writeLineInfo(std::string& ss) const for (size_t i = 0; i < lines.size(); ++i) { int delta = lines[i] - baseline[i >> logspan]; - LUAU_ASSERT(delta >= 0 && delta <= 255); + lluz_ASSERT(delta >= 0 && delta <= 255); writeByte(ss, uint8_t(delta) - lastOffset); lastOffset = uint8_t(delta); @@ -833,7 +822,7 @@ void BytecodeBuilder::writeStringTable(std::string& ss) const for (auto& p : stringTable) { - LUAU_ASSERT(p.second > 0 && p.second <= strings.size()); + lluz_ASSERT(p.second > 0 && p.second <= strings.size()); strings[p.second - 1] = p.first; } @@ -848,21 +837,21 @@ void BytecodeBuilder::writeStringTable(std::string& ss) const uint32_t BytecodeBuilder::getImportId(int32_t id0) { - LUAU_ASSERT(unsigned(id0) < 1024); + lluz_ASSERT(unsigned(id0) < 1024); return (1u << 30) | (id0 << 20); } uint32_t BytecodeBuilder::getImportId(int32_t id0, int32_t id1) { - LUAU_ASSERT(unsigned(id0 | id1) < 1024); + lluz_ASSERT(unsigned(id0 | id1) < 1024); return (2u << 30) | (id0 << 20) | (id1 << 10); } uint32_t BytecodeBuilder::getImportId(int32_t id0, int32_t id1, int32_t id2) { - LUAU_ASSERT(unsigned(id0 | id1 | id2) < 1024); + lluz_ASSERT(unsigned(id0 | id1 | id2) < 1024); return (3u << 30) | (id0 << 20) | (id1 << 10) | id2; } @@ -900,21 +889,21 @@ void BytecodeBuilder::foldJumps() // follow jump target through forward unconditional jumps // we only follow forward jumps to make sure the process terminates - uint32_t targetLabel = jumpLabel + 1 + LUAU_INSN_D(jumpInsn); - LUAU_ASSERT(targetLabel < insns.size()); + uint32_t targetLabel = jumpLabel + 1 + lluz_INSN_D(jumpInsn); + lluz_ASSERT(targetLabel < insns.size()); uint32_t targetInsn = insns[targetLabel]; - while (LUAU_INSN_OP(targetInsn) == LOP_JUMP && LUAU_INSN_D(targetInsn) >= 0) + while (lluz_INSN_OP(targetInsn) == LOP_JUMP && lluz_INSN_D(targetInsn) >= 0) { - targetLabel = targetLabel + 1 + LUAU_INSN_D(targetInsn); - LUAU_ASSERT(targetLabel < insns.size()); + targetLabel = targetLabel + 1 + lluz_INSN_D(targetInsn); + lluz_ASSERT(targetLabel < insns.size()); targetInsn = insns[targetLabel]; } int offset = int(targetLabel) - int(jumpLabel) - 1; // for unconditional jumps to RETURN, we can replace JUMP with RETURN - if (LUAU_INSN_OP(jumpInsn) == LOP_JUMP && LUAU_INSN_OP(targetInsn) == LOP_RETURN) + if (lluz_INSN_OP(jumpInsn) == LOP_JUMP && lluz_INSN_OP(targetInsn) == LOP_RETURN) { insns[jumpLabel] = targetInsn; lines[jumpLabel] = lines[targetLabel]; @@ -961,7 +950,7 @@ void BytecodeBuilder::expandJumps() std::vector newinsns; std::vector newlines; - LUAU_ASSERT(insns.size() == lines.size()); + lluz_ASSERT(insns.size() == lines.size()); newinsns.reserve(insns.size()); newlines.reserve(insns.size()); @@ -970,8 +959,8 @@ void BytecodeBuilder::expandJumps() for (size_t i = 0; i < insns.size();) { - uint8_t op = LUAU_INSN_OP(insns[i]); - LUAU_ASSERT(op < LOP__COUNT); + uint8_t op = lluz_INSN_OP(insns[i]); + lluz_ASSERT(op < LOP__COUNT); if (currentJump < jumps.size() && jumps[currentJump].source == i) { @@ -992,7 +981,7 @@ void BytecodeBuilder::expandJumps() currentJump++; } - int oplen = getOpLength(LuauOpcode(op)); + int oplen = getOpLength(lluzOpcode(op)); // copy instruction and line info to the new stream for (int j = 0; j < oplen; ++j) @@ -1006,8 +995,8 @@ void BytecodeBuilder::expandJumps() } } - LUAU_ASSERT(currentJump == jumps.size()); - LUAU_ASSERT(pendingTrampolines > 0); + lluz_ASSERT(currentJump == jumps.size()); + lluz_ASSERT(pendingTrampolines > 0); // now we need to recompute offsets for jump instructions - we could not do this in the first pass because the offsets are between *target* // instructions @@ -1022,7 +1011,7 @@ void BytecodeBuilder::expandJumps() uint32_t& insnt = newinsns[remap[jump.source] - 1]; uint32_t& insnj = newinsns[remap[jump.source]]; - LUAU_ASSERT(LUAU_INSN_OP(insnt) == LOP_JUMPX); + lluz_ASSERT(lluz_INSN_OP(insnt) == LOP_JUMPX); // patch JUMPX to JUMPX to target location; note that newoffset is the offset of the jump *relative to OP*, so we need to add 1 to make it // relative to JUMPX @@ -1040,17 +1029,17 @@ void BytecodeBuilder::expandJumps() uint32_t& insn = newinsns[remap[jump.source]]; // make sure jump instruction had the correct offset before we started - LUAU_ASSERT(LUAU_INSN_D(insn) == offset); + lluz_ASSERT(lluz_INSN_D(insn) == offset); // patch instruction with the new offset - LUAU_ASSERT(int16_t(newoffset) == newoffset); + lluz_ASSERT(int16_t(newoffset) == newoffset); insn &= 0xffff; insn |= uint16_t(newoffset) << 16; } } - LUAU_ASSERT(pendingTrampolines == 0); + lluz_ASSERT(pendingTrampolines == 0); // this was hard, but we're done. insns.swap(newinsns); @@ -1073,17 +1062,17 @@ uint8_t BytecodeBuilder::getVersion() return LBC_VERSION_TARGET; } -#ifdef LUAU_ASSERTENABLED +#ifdef lluz_ASSERTENABLED void BytecodeBuilder::validate() const { -#define VREG(v) LUAU_ASSERT(unsigned(v) < func.maxstacksize) -#define VREGRANGE(v, count) LUAU_ASSERT(unsigned(v + (count < 0 ? 0 : count)) <= func.maxstacksize) -#define VUPVAL(v) LUAU_ASSERT(unsigned(v) < func.numupvalues) -#define VCONST(v, kind) LUAU_ASSERT(unsigned(v) < constants.size() && constants[v].type == Constant::Type_##kind) -#define VCONSTANY(v) LUAU_ASSERT(unsigned(v) < constants.size()) -#define VJUMP(v) LUAU_ASSERT(size_t(i + 1 + v) < insns.size() && insnvalid[i + 1 + v]) +#define VREG(v) lluz_ASSERT(unsigned(v) < func.maxstacksize) +#define VREGRANGE(v, count) lluz_ASSERT(unsigned(v + (count < 0 ? 0 : count)) <= func.maxstacksize) +#define VUPVAL(v) lluz_ASSERT(unsigned(v) < func.numupvalues) +#define VCONST(v, kind) lluz_ASSERT(unsigned(v) < constants.size() && constants[v].type == Constant::Type_##kind) +#define VCONSTANY(v) lluz_ASSERT(unsigned(v) < constants.size()) +#define VJUMP(v) lluz_ASSERT(size_t(i + 1 + v) < insns.size() && insnvalid[i + 1 + v]) - LUAU_ASSERT(currentFunction != ~0u); + lluz_ASSERT(currentFunction != ~0u); const Function& func = functions[currentFunction]; @@ -1092,12 +1081,12 @@ void BytecodeBuilder::validate() const for (size_t i = 0; i < insns.size();) { - uint8_t op = LUAU_INSN_OP(insns[i]); + uint8_t op = lluz_INSN_OP(insns[i]); insnvalid[i] = true; - i += getOpLength(LuauOpcode(op)); - LUAU_ASSERT(i <= insns.size()); + i += getOpLength(lluzOpcode(op)); + lluz_ASSERT(i <= insns.size()); } std::vector openCaptures; @@ -1106,126 +1095,126 @@ void BytecodeBuilder::validate() const for (size_t i = 0; i < insns.size();) { uint32_t insn = insns[i]; - uint8_t op = LUAU_INSN_OP(insn); + uint8_t op = lluz_INSN_OP(insn); switch (op) { case LOP_LOADNIL: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); break; case LOP_LOADB: - VREG(LUAU_INSN_A(insn)); - LUAU_ASSERT(LUAU_INSN_B(insn) == 0 || LUAU_INSN_B(insn) == 1); - VJUMP(LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + lluz_ASSERT(lluz_INSN_B(insn) == 0 || lluz_INSN_B(insn) == 1); + VJUMP(lluz_INSN_C(insn)); break; case LOP_LOADN: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); break; case LOP_LOADK: - VREG(LUAU_INSN_A(insn)); - VCONSTANY(LUAU_INSN_D(insn)); + VREG(lluz_INSN_A(insn)); + VCONSTANY(lluz_INSN_D(insn)); break; case LOP_MOVE: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); break; case LOP_GETGLOBAL: case LOP_SETGLOBAL: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); VCONST(insns[i + 1], String); break; case LOP_GETUPVAL: case LOP_SETUPVAL: - VREG(LUAU_INSN_A(insn)); - VUPVAL(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VUPVAL(lluz_INSN_B(insn)); break; case LOP_CLOSEUPVALS: - VREG(LUAU_INSN_A(insn)); - while (openCaptures.size() && openCaptures.back() >= LUAU_INSN_A(insn)) + VREG(lluz_INSN_A(insn)); + while (openCaptures.size() && openCaptures.back() >= lluz_INSN_A(insn)) openCaptures.pop_back(); break; case LOP_GETIMPORT: - VREG(LUAU_INSN_A(insn)); - VCONST(LUAU_INSN_D(insn), Import); + VREG(lluz_INSN_A(insn)); + VCONST(lluz_INSN_D(insn), Import); // TODO: check insn[i + 1] for conformance with 10-bit import encoding break; case LOP_GETTABLE: case LOP_SETTABLE: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VREG(LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VREG(lluz_INSN_C(insn)); break; case LOP_GETTABLEKS: case LOP_SETTABLEKS: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); VCONST(insns[i + 1], String); break; case LOP_GETTABLEN: case LOP_SETTABLEN: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); break; case LOP_NEWCLOSURE: { - VREG(LUAU_INSN_A(insn)); - LUAU_ASSERT(unsigned(LUAU_INSN_D(insn)) < protos.size()); - LUAU_ASSERT(protos[LUAU_INSN_D(insn)] < functions.size()); - unsigned int numupvalues = functions[protos[LUAU_INSN_D(insn)]].numupvalues; + VREG(lluz_INSN_A(insn)); + lluz_ASSERT(unsigned(lluz_INSN_D(insn)) < protos.size()); + lluz_ASSERT(protos[lluz_INSN_D(insn)] < functions.size()); + unsigned int numupvalues = functions[protos[lluz_INSN_D(insn)]].numupvalues; for (unsigned int j = 0; j < numupvalues; ++j) { - LUAU_ASSERT(i + 1 + j < insns.size()); + lluz_ASSERT(i + 1 + j < insns.size()); uint32_t cinsn = insns[i + 1 + j]; - LUAU_ASSERT(LUAU_INSN_OP(cinsn) == LOP_CAPTURE); + lluz_ASSERT(lluz_INSN_OP(cinsn) == LOP_CAPTURE); } } break; case LOP_NAMECALL: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); VCONST(insns[i + 1], String); - LUAU_ASSERT(LUAU_INSN_OP(insns[i + 2]) == LOP_CALL); + lluz_ASSERT(lluz_INSN_OP(insns[i + 2]) == LOP_CALL); break; case LOP_CALL: { - int nparams = LUAU_INSN_B(insn) - 1; - int nresults = LUAU_INSN_C(insn) - 1; - VREG(LUAU_INSN_A(insn)); - VREGRANGE(LUAU_INSN_A(insn) + 1, nparams); // 1..nparams - VREGRANGE(LUAU_INSN_A(insn), nresults); // 1..nresults + int nparams = lluz_INSN_B(insn) - 1; + int nresults = lluz_INSN_C(insn) - 1; + VREG(lluz_INSN_A(insn)); + VREGRANGE(lluz_INSN_A(insn) + 1, nparams); // 1..nparams + VREGRANGE(lluz_INSN_A(insn), nresults); // 1..nresults } break; case LOP_RETURN: { - int nresults = LUAU_INSN_B(insn) - 1; - VREGRANGE(LUAU_INSN_A(insn), nresults); // 0..nresults-1 + int nresults = lluz_INSN_B(insn) - 1; + VREGRANGE(lluz_INSN_A(insn), nresults); // 0..nresults-1 } break; case LOP_JUMP: - VJUMP(LUAU_INSN_D(insn)); + VJUMP(lluz_INSN_D(insn)); break; case LOP_JUMPIF: case LOP_JUMPIFNOT: - VREG(LUAU_INSN_A(insn)); - VJUMP(LUAU_INSN_D(insn)); + VREG(lluz_INSN_A(insn)); + VJUMP(lluz_INSN_D(insn)); break; case LOP_JUMPIFEQ: @@ -1234,16 +1223,16 @@ void BytecodeBuilder::validate() const case LOP_JUMPIFNOTEQ: case LOP_JUMPIFNOTLE: case LOP_JUMPIFNOTLT: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); VREG(insns[i + 1]); - VJUMP(LUAU_INSN_D(insn)); + VJUMP(lluz_INSN_D(insn)); break; case LOP_JUMPIFEQK: case LOP_JUMPIFNOTEQK: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); VCONSTANY(insns[i + 1]); - VJUMP(LUAU_INSN_D(insn)); + VJUMP(lluz_INSN_D(insn)); break; case LOP_ADD: @@ -1252,9 +1241,9 @@ void BytecodeBuilder::validate() const case LOP_DIV: case LOP_MOD: case LOP_POW: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VREG(LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VREG(lluz_INSN_C(insn)); break; case LOP_ADDK: @@ -1263,152 +1252,152 @@ void BytecodeBuilder::validate() const case LOP_DIVK: case LOP_MODK: case LOP_POWK: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VCONST(LUAU_INSN_C(insn), Number); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VCONST(lluz_INSN_C(insn), Number); break; case LOP_AND: case LOP_OR: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VREG(LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VREG(lluz_INSN_C(insn)); break; case LOP_ANDK: case LOP_ORK: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VCONSTANY(LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VCONSTANY(lluz_INSN_C(insn)); break; case LOP_CONCAT: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); - VREG(LUAU_INSN_C(insn)); - LUAU_ASSERT(LUAU_INSN_B(insn) <= LUAU_INSN_C(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); + VREG(lluz_INSN_C(insn)); + lluz_ASSERT(lluz_INSN_B(insn) <= lluz_INSN_C(insn)); break; case LOP_NOT: case LOP_MINUS: case LOP_LENGTH: - VREG(LUAU_INSN_A(insn)); - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_A(insn)); + VREG(lluz_INSN_B(insn)); break; case LOP_NEWTABLE: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); break; case LOP_DUPTABLE: - VREG(LUAU_INSN_A(insn)); - VCONST(LUAU_INSN_D(insn), Table); + VREG(lluz_INSN_A(insn)); + VCONST(lluz_INSN_D(insn), Table); break; case LOP_SETLIST: { - int count = LUAU_INSN_C(insn) - 1; - VREG(LUAU_INSN_A(insn)); - VREGRANGE(LUAU_INSN_B(insn), count); + int count = lluz_INSN_C(insn) - 1; + VREG(lluz_INSN_A(insn)); + VREGRANGE(lluz_INSN_B(insn), count); } break; case LOP_FORNPREP: case LOP_FORNLOOP: // for loop protocol: A, A+1, A+2 are used for iteration - VREG(LUAU_INSN_A(insn) + 2); - VJUMP(LUAU_INSN_D(insn)); + VREG(lluz_INSN_A(insn) + 2); + VJUMP(lluz_INSN_D(insn)); break; case LOP_FORGPREP: // forg loop protocol: A, A+1, A+2 are used for iteration protocol; A+3, ... are loop variables - VREG(LUAU_INSN_A(insn) + 2 + 1); - VJUMP(LUAU_INSN_D(insn)); + VREG(lluz_INSN_A(insn) + 2 + 1); + VJUMP(lluz_INSN_D(insn)); break; case LOP_FORGLOOP: // forg loop protocol: A, A+1, A+2 are used for iteration protocol; A+3, ... are loop variables - VREG(LUAU_INSN_A(insn) + 2 + uint8_t(insns[i + 1])); - VJUMP(LUAU_INSN_D(insn)); - LUAU_ASSERT(uint8_t(insns[i + 1]) >= 1); + VREG(lluz_INSN_A(insn) + 2 + uint8_t(insns[i + 1])); + VJUMP(lluz_INSN_D(insn)); + lluz_ASSERT(uint8_t(insns[i + 1]) >= 1); break; case LOP_FORGPREP_INEXT: case LOP_FORGLOOP_INEXT: case LOP_FORGPREP_NEXT: case LOP_FORGLOOP_NEXT: - VREG(LUAU_INSN_A(insn) + 4); // forg loop protocol: A, A+1, A+2 are used for iteration protocol; A+3, A+4 are loop variables - VJUMP(LUAU_INSN_D(insn)); + VREG(lluz_INSN_A(insn) + 4); // forg loop protocol: A, A+1, A+2 are used for iteration protocol; A+3, A+4 are loop variables + VJUMP(lluz_INSN_D(insn)); break; case LOP_GETVARARGS: { - int nresults = LUAU_INSN_B(insn) - 1; - VREGRANGE(LUAU_INSN_A(insn), nresults); // 0..nresults-1 + int nresults = lluz_INSN_B(insn) - 1; + VREGRANGE(lluz_INSN_A(insn), nresults); // 0..nresults-1 } break; case LOP_DUPCLOSURE: { - VREG(LUAU_INSN_A(insn)); - VCONST(LUAU_INSN_D(insn), Closure); - unsigned int proto = constants[LUAU_INSN_D(insn)].valueClosure; - LUAU_ASSERT(proto < functions.size()); + VREG(lluz_INSN_A(insn)); + VCONST(lluz_INSN_D(insn), Closure); + unsigned int proto = constants[lluz_INSN_D(insn)].valueClosure; + lluz_ASSERT(proto < functions.size()); unsigned int numupvalues = functions[proto].numupvalues; for (unsigned int j = 0; j < numupvalues; ++j) { - LUAU_ASSERT(i + 1 + j < insns.size()); + lluz_ASSERT(i + 1 + j < insns.size()); uint32_t cinsn = insns[i + 1 + j]; - LUAU_ASSERT(LUAU_INSN_OP(cinsn) == LOP_CAPTURE); - LUAU_ASSERT(LUAU_INSN_A(cinsn) == LCT_VAL || LUAU_INSN_A(cinsn) == LCT_UPVAL); + lluz_ASSERT(lluz_INSN_OP(cinsn) == LOP_CAPTURE); + lluz_ASSERT(lluz_INSN_A(cinsn) == LCT_VAL || lluz_INSN_A(cinsn) == LCT_UPVAL); } } break; case LOP_PREPVARARGS: - LUAU_ASSERT(LUAU_INSN_A(insn) == func.numparams); - LUAU_ASSERT(func.isvararg); + lluz_ASSERT(lluz_INSN_A(insn) == func.numparams); + lluz_ASSERT(func.isvararg); break; case LOP_BREAK: break; case LOP_JUMPBACK: - VJUMP(LUAU_INSN_D(insn)); + VJUMP(lluz_INSN_D(insn)); break; case LOP_LOADKX: - VREG(LUAU_INSN_A(insn)); + VREG(lluz_INSN_A(insn)); VCONSTANY(insns[i + 1]); break; case LOP_JUMPX: - VJUMP(LUAU_INSN_E(insn)); + VJUMP(lluz_INSN_E(insn)); break; case LOP_FASTCALL: - VJUMP(LUAU_INSN_C(insn)); - LUAU_ASSERT(LUAU_INSN_OP(insns[i + 1 + LUAU_INSN_C(insn)]) == LOP_CALL); + VJUMP(lluz_INSN_C(insn)); + lluz_ASSERT(lluz_INSN_OP(insns[i + 1 + lluz_INSN_C(insn)]) == LOP_CALL); break; case LOP_FASTCALL1: - VREG(LUAU_INSN_B(insn)); - VJUMP(LUAU_INSN_C(insn)); - LUAU_ASSERT(LUAU_INSN_OP(insns[i + 1 + LUAU_INSN_C(insn)]) == LOP_CALL); + VREG(lluz_INSN_B(insn)); + VJUMP(lluz_INSN_C(insn)); + lluz_ASSERT(lluz_INSN_OP(insns[i + 1 + lluz_INSN_C(insn)]) == LOP_CALL); break; case LOP_FASTCALL2: - VREG(LUAU_INSN_B(insn)); - VJUMP(LUAU_INSN_C(insn)); - LUAU_ASSERT(LUAU_INSN_OP(insns[i + 1 + LUAU_INSN_C(insn)]) == LOP_CALL); + VREG(lluz_INSN_B(insn)); + VJUMP(lluz_INSN_C(insn)); + lluz_ASSERT(lluz_INSN_OP(insns[i + 1 + lluz_INSN_C(insn)]) == LOP_CALL); VREG(insns[i + 1]); break; case LOP_FASTCALL2K: - VREG(LUAU_INSN_B(insn)); - VJUMP(LUAU_INSN_C(insn)); - LUAU_ASSERT(LUAU_INSN_OP(insns[i + 1 + LUAU_INSN_C(insn)]) == LOP_CALL); + VREG(lluz_INSN_B(insn)); + VJUMP(lluz_INSN_C(insn)); + lluz_ASSERT(lluz_INSN_OP(insns[i + 1 + lluz_INSN_C(insn)]) == LOP_CALL); VCONSTANY(insns[i + 1]); break; @@ -1416,39 +1405,39 @@ void BytecodeBuilder::validate() const break; case LOP_CAPTURE: - switch (LUAU_INSN_A(insn)) + switch (lluz_INSN_A(insn)) { case LCT_VAL: - VREG(LUAU_INSN_B(insn)); + VREG(lluz_INSN_B(insn)); break; case LCT_REF: - VREG(LUAU_INSN_B(insn)); - openCaptures.push_back(LUAU_INSN_B(insn)); + VREG(lluz_INSN_B(insn)); + openCaptures.push_back(lluz_INSN_B(insn)); break; case LCT_UPVAL: - VUPVAL(LUAU_INSN_B(insn)); + VUPVAL(lluz_INSN_B(insn)); break; default: - LUAU_ASSERT(!"Unsupported capture type"); + lluz_ASSERT(!XorStr("Unsupported capture type")); } break; default: - LUAU_ASSERT(!"Unsupported opcode"); + lluz_ASSERT(!XorStr("Unsupported opcode")); } - i += getOpLength(LuauOpcode(op)); - LUAU_ASSERT(i <= insns.size()); + i += getOpLength(lluzOpcode(op)); + lluz_ASSERT(i <= insns.size()); } // all CAPTURE REF instructions must have a CLOSEUPVALS instruction after them in the bytecode stream // this doesn't guarantee safety as it doesn't perform basic block based analysis, but if this fails // then the bytecode is definitely unsafe to run since the compiler won't generate backwards branches // except for loop edges - LUAU_ASSERT(openCaptures.empty()); + lluz_ASSERT(openCaptures.empty()); #undef VREG #undef VREGEND @@ -1463,94 +1452,94 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result, { uint32_t insn = *code++; - switch (LUAU_INSN_OP(insn)) + switch (lluz_INSN_OP(insn)) { case LOP_LOADNIL: - formatAppend(result, "LOADNIL R%d\n", LUAU_INSN_A(insn)); + formatAppend(result, "LOADNIL R%d\n", lluz_INSN_A(insn)); break; case LOP_LOADB: - if (LUAU_INSN_C(insn)) - formatAppend(result, "LOADB R%d %d +%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + if (lluz_INSN_C(insn)) + formatAppend(result, "LOADB R%d %d +%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); else - formatAppend(result, "LOADB R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "LOADB R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_LOADN: - formatAppend(result, "LOADN R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "LOADN R%d %d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); break; case LOP_LOADK: - formatAppend(result, "LOADK R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "LOADK R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); break; case LOP_MOVE: - formatAppend(result, "MOVE R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "MOVE R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_GETGLOBAL: - formatAppend(result, "GETGLOBAL R%d K%d\n", LUAU_INSN_A(insn), *code++); + formatAppend(result, "GETGLOBAL R%d K%d\n", lluz_INSN_A(insn), *code++); break; case LOP_SETGLOBAL: - formatAppend(result, "SETGLOBAL R%d K%d\n", LUAU_INSN_A(insn), *code++); + formatAppend(result, "SETGLOBAL R%d K%d\n", lluz_INSN_A(insn), *code++); break; case LOP_GETUPVAL: - formatAppend(result, "GETUPVAL R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "GETUPVAL R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_SETUPVAL: - formatAppend(result, "SETUPVAL R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "SETUPVAL R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_CLOSEUPVALS: - formatAppend(result, "CLOSEUPVALS R%d\n", LUAU_INSN_A(insn)); + formatAppend(result, "CLOSEUPVALS R%d\n", lluz_INSN_A(insn)); break; case LOP_GETIMPORT: - formatAppend(result, "GETIMPORT R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "GETIMPORT R%d %d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); code++; // AUX break; case LOP_GETTABLE: - formatAppend(result, "GETTABLE R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "GETTABLE R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_SETTABLE: - formatAppend(result, "SETTABLE R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "SETTABLE R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_GETTABLEKS: - formatAppend(result, "GETTABLEKS R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), *code++); + formatAppend(result, "GETTABLEKS R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), *code++); break; case LOP_SETTABLEKS: - formatAppend(result, "SETTABLEKS R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), *code++); + formatAppend(result, "SETTABLEKS R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), *code++); break; case LOP_GETTABLEN: - formatAppend(result, "GETTABLEN R%d R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn) + 1); + formatAppend(result, "GETTABLEN R%d R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn) + 1); break; case LOP_SETTABLEN: - formatAppend(result, "SETTABLEN R%d R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn) + 1); + formatAppend(result, "SETTABLEN R%d R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn) + 1); break; case LOP_NEWCLOSURE: - formatAppend(result, "NEWCLOSURE R%d P%d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "NEWCLOSURE R%d P%d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); break; case LOP_NAMECALL: - formatAppend(result, "NAMECALL R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), *code++); + formatAppend(result, "NAMECALL R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), *code++); break; case LOP_CALL: - formatAppend(result, "CALL R%d %d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn) - 1, LUAU_INSN_C(insn) - 1); + formatAppend(result, "CALL R%d %d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn) - 1, lluz_INSN_C(insn) - 1); break; case LOP_RETURN: - formatAppend(result, "RETURN R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn) - 1); + formatAppend(result, "RETURN R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn) - 1); break; case LOP_JUMP: @@ -1558,172 +1547,172 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result, break; case LOP_JUMPIF: - formatAppend(result, "JUMPIF R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "JUMPIF R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_JUMPIFNOT: - formatAppend(result, "JUMPIFNOT R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "JUMPIFNOT R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_JUMPIFEQ: - formatAppend(result, "JUMPIFEQ R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFEQ R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFLE: - formatAppend(result, "JUMPIFLE R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFLE R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFLT: - formatAppend(result, "JUMPIFLT R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFLT R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFNOTEQ: - formatAppend(result, "JUMPIFNOTEQ R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFNOTEQ R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFNOTLE: - formatAppend(result, "JUMPIFNOTLE R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFNOTLE R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFNOTLT: - formatAppend(result, "JUMPIFNOTLT R%d R%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFNOTLT R%d R%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_ADD: - formatAppend(result, "ADD R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "ADD R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_SUB: - formatAppend(result, "SUB R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "SUB R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_MUL: - formatAppend(result, "MUL R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "MUL R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_DIV: - formatAppend(result, "DIV R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "DIV R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_MOD: - formatAppend(result, "MOD R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "MOD R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_POW: - formatAppend(result, "POW R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "POW R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_ADDK: - formatAppend(result, "ADDK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "ADDK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_SUBK: - formatAppend(result, "SUBK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "SUBK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_MULK: - formatAppend(result, "MULK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "MULK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_DIVK: - formatAppend(result, "DIVK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "DIVK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_MODK: - formatAppend(result, "MODK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "MODK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_POWK: - formatAppend(result, "POWK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "POWK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_AND: - formatAppend(result, "AND R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "AND R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_OR: - formatAppend(result, "OR R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "OR R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_ANDK: - formatAppend(result, "ANDK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "ANDK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_ORK: - formatAppend(result, "ORK R%d R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "ORK R%d R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_CONCAT: - formatAppend(result, "CONCAT R%d R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn)); + formatAppend(result, "CONCAT R%d R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn)); break; case LOP_NOT: - formatAppend(result, "NOT R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "NOT R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_MINUS: - formatAppend(result, "MINUS R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "MINUS R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_LENGTH: - formatAppend(result, "LENGTH R%d R%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn)); + formatAppend(result, "LENGTH R%d R%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn)); break; case LOP_NEWTABLE: - formatAppend(result, "NEWTABLE R%d %d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn) == 0 ? 0 : 1 << (LUAU_INSN_B(insn) - 1), *code++); + formatAppend(result, "NEWTABLE R%d %d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn) == 0 ? 0 : 1 << (lluz_INSN_B(insn) - 1), *code++); break; case LOP_DUPTABLE: - formatAppend(result, "DUPTABLE R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "DUPTABLE R%d %d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); break; case LOP_SETLIST: - formatAppend(result, "SETLIST R%d R%d %d [%d]\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), LUAU_INSN_C(insn) - 1, *code++); + formatAppend(result, "SETLIST R%d R%d %d [%d]\n", lluz_INSN_A(insn), lluz_INSN_B(insn), lluz_INSN_C(insn) - 1, *code++); break; case LOP_FORNPREP: - formatAppend(result, "FORNPREP R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORNPREP R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORNLOOP: - formatAppend(result, "FORNLOOP R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORNLOOP R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORGPREP: - formatAppend(result, "FORGPREP R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORGPREP R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORGLOOP: - formatAppend(result, "FORGLOOP R%d L%d %d%s\n", LUAU_INSN_A(insn), targetLabel, uint8_t(*code), int(*code) < 0 ? " [inext]" : ""); + formatAppend(result, XorStr("FORGLOOP R%d L%d %d%s\n", lluz_INSN_A(insn), targetLabel, uint8_t(*code), int(*code) < 0 ? " [inext]" : "")); code++; break; case LOP_FORGPREP_INEXT: - formatAppend(result, "FORGPREP_INEXT R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORGPREP_INEXT R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORGLOOP_INEXT: - formatAppend(result, "FORGLOOP_INEXT R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORGLOOP_INEXT R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORGPREP_NEXT: - formatAppend(result, "FORGPREP_NEXT R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORGPREP_NEXT R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FORGLOOP_NEXT: - formatAppend(result, "FORGLOOP_NEXT R%d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FORGLOOP_NEXT R%d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_GETVARARGS: - formatAppend(result, "GETVARARGS R%d %d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn) - 1); + formatAppend(result, "GETVARARGS R%d %d\n", lluz_INSN_A(insn), lluz_INSN_B(insn) - 1); break; case LOP_DUPCLOSURE: - formatAppend(result, "DUPCLOSURE R%d K%d\n", LUAU_INSN_A(insn), LUAU_INSN_D(insn)); + formatAppend(result, "DUPCLOSURE R%d K%d\n", lluz_INSN_A(insn), lluz_INSN_D(insn)); break; case LOP_BREAK: - formatAppend(result, "BREAK\n"); + formatAppend(result, XorStr("BREAK\n")); break; case LOP_JUMPBACK: @@ -1731,7 +1720,7 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result, break; case LOP_LOADKX: - formatAppend(result, "LOADKX R%d K%d\n", LUAU_INSN_A(insn), *code++); + formatAppend(result, "LOADKX R%d K%d\n", lluz_INSN_A(insn), *code++); break; case LOP_JUMPX: @@ -1739,48 +1728,48 @@ void BytecodeBuilder::dumpInstruction(const uint32_t* code, std::string& result, break; case LOP_FASTCALL: - formatAppend(result, "FASTCALL %d L%d\n", LUAU_INSN_A(insn), targetLabel); + formatAppend(result, "FASTCALL %d L%d\n", lluz_INSN_A(insn), targetLabel); break; case LOP_FASTCALL1: - formatAppend(result, "FASTCALL1 %d R%d L%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), targetLabel); + formatAppend(result, "FASTCALL1 %d R%d L%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), targetLabel); break; case LOP_FASTCALL2: { uint32_t aux = *code++; - formatAppend(result, "FASTCALL2 %d R%d R%d L%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), aux, targetLabel); + formatAppend(result, "FASTCALL2 %d R%d R%d L%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), aux, targetLabel); break; } case LOP_FASTCALL2K: { uint32_t aux = *code++; - formatAppend(result, "FASTCALL2K %d R%d K%d L%d\n", LUAU_INSN_A(insn), LUAU_INSN_B(insn), aux, targetLabel); + formatAppend(result, "FASTCALL2K %d R%d K%d L%d\n", lluz_INSN_A(insn), lluz_INSN_B(insn), aux, targetLabel); break; } case LOP_COVERAGE: - formatAppend(result, "COVERAGE\n"); + formatAppend(result, XorStr("COVERAGE\n")); break; 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" + lluz_INSN_A(insn) == LCT_UPVAL ? "UPVAL" + : lluz_INSN_A(insn) == LCT_REF ? "REF" + : lluz_INSN_A(insn) == LCT_VAL ? "VAL" : "", - LUAU_INSN_A(insn) == LCT_UPVAL ? 'U' : 'R', LUAU_INSN_B(insn)); + lluz_INSN_A(insn) == LCT_UPVAL ? 'U' : 'R', lluz_INSN_B(insn)); break; case LOP_JUMPIFEQK: - formatAppend(result, "JUMPIFEQK R%d K%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFEQK R%d K%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; case LOP_JUMPIFNOTEQK: - formatAppend(result, "JUMPIFNOTEQK R%d K%d L%d\n", LUAU_INSN_A(insn), *code++, targetLabel); + formatAppend(result, "JUMPIFNOTEQK R%d K%d L%d\n", lluz_INSN_A(insn), *code++, targetLabel); break; default: - LUAU_ASSERT(!"Unsupported opcode"); + lluz_ASSERT(!"Unsupported opcode"); } } @@ -1800,9 +1789,9 @@ std::string BytecodeBuilder::dumpCurrentFunction() const { const DebugLocal& l = debugLocals[i]; - LUAU_ASSERT(l.startpc < l.endpc); - LUAU_ASSERT(l.startpc < lines.size()); - LUAU_ASSERT(l.endpc <= lines.size()); // endpc is exclusive in the debug info, but it's more intuitive to print inclusive data + lluz_ASSERT(l.startpc < l.endpc); + lluz_ASSERT(l.startpc < lines.size()); + lluz_ASSERT(l.endpc <= lines.size()); // endpc is exclusive in the debug info, but it's more intuitive to print inclusive data // it would be nice to emit name as well but it requires reverse lookup through stringtable formatAppend(result, "local %d: reg %d, start pc %d line %d, end pc %d line %d\n", int(i), l.reg, l.startpc, lines[l.startpc], @@ -1819,12 +1808,12 @@ std::string BytecodeBuilder::dumpCurrentFunction() const if (target >= 0) { - LUAU_ASSERT(size_t(target) < insns.size()); + lluz_ASSERT(size_t(target) < insns.size()); labels[target] = 0; } - i += getOpLength(LuauOpcode(LUAU_INSN_OP(insns[i]))); - LUAU_ASSERT(i <= insns.size()); + i += getOpLength(lluzOpcode(lluz_INSN_OP(insns[i]))); + lluz_ASSERT(i <= insns.size()); } int nextLabel = 0; @@ -1837,7 +1826,7 @@ std::string BytecodeBuilder::dumpCurrentFunction() const for (size_t i = 0; i < insns.size();) { const uint32_t* code = &insns[i]; - uint8_t op = LUAU_INSN_OP(*code); + uint8_t op = lluz_INSN_OP(*code); if (op == LOP_PREPVARARGS) { @@ -1861,7 +1850,7 @@ std::string BytecodeBuilder::dumpCurrentFunction() const if (line > 0 && line != lastLine) { - LUAU_ASSERT(size_t(line - 1) < dumpSource.size()); + lluz_ASSERT(size_t(line - 1) < dumpSource.size()); formatAppend(result, "%5d: %s\n", line, dumpSource[line - 1].c_str()); lastLine = line; } @@ -1877,8 +1866,8 @@ std::string BytecodeBuilder::dumpCurrentFunction() const dumpInstruction(code, result, target >= 0 ? labels[target] : -1); - i += getOpLength(LuauOpcode(op)); - LUAU_ASSERT(i <= insns.size()); + i += getOpLength(lluzOpcode(op)); + lluz_ASSERT(i <= insns.size()); } return result; @@ -1912,7 +1901,7 @@ void BytecodeBuilder::setDumpSource(const std::string& source) std::string BytecodeBuilder::dumpFunction(uint32_t id) const { - LUAU_ASSERT(id < functions.size()); + lluz_ASSERT(id < functions.size()); return functions[id].dump; } @@ -1934,4 +1923,4 @@ std::string BytecodeBuilder::dumpEverything() const return result; } -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 4be54378..8b1d5153 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -1,10 +1,10 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details -#include "Luau/Compiler.h" +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details +#include "lluz/Compiler.h" -#include "Luau/Parser.h" -#include "Luau/BytecodeBuilder.h" -#include "Luau/Common.h" -#include "Luau/TimeTrace.h" +#include "lluz/Parser.h" +#include "lluz/BytecodeBuilder.h" +#include "lluz/Common.h" +#include "lluz/TimeTrace.h" #include "Builtins.h" #include "ConstantFolding.h" @@ -12,25 +12,25 @@ #include "TableShape.h" #include "ValueTracking.h" +#include "..\..\..\..\Security\XorString.h" + #include #include #include -LUAU_FASTINTVARIABLE(LuauCompileLoopUnrollThreshold, 25) -LUAU_FASTINTVARIABLE(LuauCompileLoopUnrollThresholdMaxBoost, 300) +lluz_FASTINTVARIABLE(LluCompileLoopUnrollThreshold, 25) +lluz_FASTINTVARIABLE(LluCompileLoopUnrollThresholdMaxBoost, 300) -LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25) -LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300) -LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5) +lluz_FASTINTVARIABLE(LluCompileInlineThreshold, 25) +lluz_FASTINTVARIABLE(LluCompileInlineThresholdMaxBoost, 300) +lluz_FASTINTVARIABLE(LluCompileInlineDepth, 5) -LUAU_FASTFLAGVARIABLE(LuauCompileNoIpairs, false) +lluz_FASTFLAGVARIABLE(LluCompileNoIpairs, false) -LUAU_FASTFLAGVARIABLE(LuauCompileFreeReassign, false) - -namespace Luau +namespace lluz { -using namespace Luau::Compile; +using namespace lluz::Compile; static const uint32_t kMaxRegisterCount = 255; static const uint32_t kMaxUpvalueCount = 200; @@ -55,7 +55,7 @@ const Location& CompileError::getLocation() const } // NOINLINE is used to limit the stack cost of this function due to std::string object / exception plumbing -LUAU_NOINLINE void CompileError::raise(const Location& location, const char* format, ...) +lluz_NOINLINE void CompileError::raise(const Location& location, const char* format, ...) { va_list args; va_start(args, format); @@ -67,19 +67,13 @@ LUAU_NOINLINE void CompileError::raise(const Location& location, const char* for static BytecodeBuilder::StringRef sref(AstName name) { - LUAU_ASSERT(name.value); + lluz_ASSERT(name.value); return {name.value, strlen(name.value)}; } static BytecodeBuilder::StringRef sref(AstArray data) { - LUAU_ASSERT(data.data); - return {data.data, data.size}; -} - -static BytecodeBuilder::StringRef sref(AstArray data) -{ - LUAU_ASSERT(data.data); + lluz_ASSERT(data.data); return {data.data, data.size}; } @@ -97,7 +91,6 @@ struct Compiler , constants(nullptr) , locstants(nullptr) , tableShapes(nullptr) - , builtins(nullptr) { // preallocate some buffers that are very likely to grow anyway; this works around std::vector's inefficient growth policy for small arrays localStack.reserve(16); @@ -119,7 +112,7 @@ struct Compiler if (upvals.size() >= kMaxUpvalueCount) CompileError::raise( - local->location, "Out of upvalue registers when trying to allocate %s: exceeded limit %d", local->name.value, kMaxUpvalueCount); + local->location, XorStr("Out of upvalue registers when trying to allocate %s: exceeded limit %d"), local->name.value, kMaxUpvalueCount); // mark local as captured so that closeLocals emits LOP_CLOSEUPVALS accordingly Variable* v = variables.find(local); @@ -146,7 +139,7 @@ struct Compiler void emitLoadK(uint8_t target, int32_t cid) { - LUAU_ASSERT(cid >= 0); + lluz_ASSERT(cid >= 0); if (cid < 32768) { @@ -180,13 +173,13 @@ struct Compiler uint32_t compileFunction(AstExprFunction* func) { - LUAU_TIMETRACE_SCOPE("Compiler::compileFunction", "Compiler"); + lluz_TIMETRACE_SCOPE(XorStr("Compiler::compileFunction", "Compiler")); if (func->debugname.value) - LUAU_TIMETRACE_ARGUMENT("name", func->debugname.value); + lluz_TIMETRACE_ARGUMENT("name", func->debugname.value); - LUAU_ASSERT(!functions.contains(func)); - LUAU_ASSERT(regTop == 0 && stackSize == 0 && localStack.empty() && upvals.empty()); + lluz_ASSERT(!functions.contains(func)); + lluz_ASSERT(regTop == 0 && stackSize == 0 && localStack.empty() && upvals.empty()); RegScope rs(this); @@ -254,7 +247,7 @@ struct Compiler { f.canInline = true; f.stackSize = stackSize; - f.costModel = modelCost(func->body, func->args.data, func->args.size, builtins); + f.costModel = modelCost(func->body, func->args.data, func->args.size); // track functions that only ever return a single value so that we can convert multret calls to fixedret calls if (allPathsEndWithReturn(func->body)) @@ -271,44 +264,23 @@ struct Compiler return fid; } - // returns true if node can return multiple values; may conservatively return true even if expr is known to return just a single value - bool isExprMultRet(AstExpr* node) - { - AstExprCall* expr = node->as(); - if (!expr) - return node->is(); - - // conservative version, optimized for compilation throughput - if (options.optimizationLevel <= 1) - return true; - - // handles builtin calls that can be constant-folded - // without this we may omit some optimizations eg compiling fast calls without use of FASTCALL2K - if (isConstant(expr)) - return false; - - // handles local function calls where we know only one argument is returned - AstExprFunction* func = getFunctionExpr(expr->func); - Function* fi = func ? functions.find(func) : nullptr; - - if (fi && fi->returnsOne) - return false; - - // unrecognized call, so we conservatively assume multret - return true; - } - // note: this doesn't just clobber target (assuming it's temp), but also clobbers *all* allocated registers >= target! // this is important to be able to support "multret" semantics due to Lua call frame structure bool compileExprTempMultRet(AstExpr* node, uint8_t target) { if (AstExprCall* expr = node->as()) { - // Optimization: convert multret calls that always return one value to fixedret calls; this facilitates inlining/constant folding - if (options.optimizationLevel >= 2 && !isExprMultRet(node)) + // Optimization: convert multret calls to functions that always return one value to fixedret calls; this facilitates inlining + if (options.optimizationLevel >= 2) { - compileExprTemp(node, target); - return false; + AstExprFunction* func = getFunctionExpr(expr->func); + Function* fi = func ? functions.find(func) : nullptr; + + if (fi && fi->returnsOne) + { + compileExprTemp(node, target); + return false; + } } // We temporarily swap out regTop to have targetTop work correctly... @@ -345,7 +317,7 @@ struct Compiler void compileExprVarargs(AstExprVarargs* expr, uint8_t target, uint8_t targetCount, bool multRet = false) { - LUAU_ASSERT(!multRet || unsigned(target + targetCount) == regTop); + lluz_ASSERT(!multRet || unsigned(target + targetCount) == regTop); setDebugLine(expr); // normally compileExpr sets up line info, but compileExprCall can be called directly @@ -354,9 +326,9 @@ struct Compiler void compileExprSelectVararg(AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop, bool multRet, uint8_t regs) { - LUAU_ASSERT(targetCount == 1); - LUAU_ASSERT(!expr->self); - LUAU_ASSERT(expr->args.size == 2 && expr->args.data[1]->is()); + lluz_ASSERT(targetCount == 1); + lluz_ASSERT(!expr->self); + lluz_ASSERT(expr->args.size == 2 && expr->args.data[1]->is()); AstExpr* arg = expr->args.data[0]; @@ -385,7 +357,7 @@ struct Compiler size_t callLabel = bytecode.emitLabel(); if (!bytecode.patchSkipC(fastcallLabel, callLabel)) - CompileError::raise(expr->func->location, "Exceeded jump distance limit; simplify the code to compile"); + CompileError::raise(expr->func->location, XorStr("Exceeded jump distance limit; simplify the code to compile")); // note, this is always multCall (last argument is variadic) bytecode.emitABC(LOP_CALL, regs, 0, multRet ? 0 : uint8_t(targetCount + 1)); @@ -400,10 +372,10 @@ struct Compiler void compileExprFastcallN(AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop, bool multRet, uint8_t regs, int bfid) { - LUAU_ASSERT(!expr->self); - LUAU_ASSERT(expr->args.size <= 2); + lluz_ASSERT(!expr->self); + lluz_ASSERT(expr->args.size <= 2); - LuauOpcode opc = expr->args.size == 1 ? LOP_FASTCALL1 : LOP_FASTCALL2; + lluzOpcode opc = expr->args.size == 1 ? LOP_FASTCALL1 : LOP_FASTCALL2; uint32_t args[2] = {}; @@ -458,7 +430,7 @@ struct Compiler // FASTCALL will skip over the instructions needed to compute function and jump over CALL which must immediately follow the instruction // sequence after FASTCALL if (!bytecode.patchSkipC(fastcallLabel, callLabel)) - CompileError::raise(expr->func->location, "Exceeded jump distance limit; simplify the code to compile"); + CompileError::raise(expr->func->location, XorStr("Exceeded jump distance limit; simplify the code to compile")); bytecode.emitABC(LOP_CALL, regs, uint8_t(expr->args.size + 1), multRet ? 0 : uint8_t(targetCount + 1)); @@ -474,19 +446,19 @@ struct Compiler int thresholdMaxBoost, int depthLimit) { Function* fi = functions.find(func); - LUAU_ASSERT(fi); + lluz_ASSERT(fi); // make sure we have enough register space if (regTop > 128 || fi->stackSize > 32) { - bytecode.addDebugRemark("inlining failed: high register pressure"); + bytecode.addDebugRemark(XorStr("inlining failed: high register pressure")); return false; } // we should ideally aggregate the costs during recursive inlining, but for now simply limit the depth if (int(inlineFrames.size()) >= depthLimit) { - bytecode.addDebugRemark("inlining failed: too many inlined frames"); + bytecode.addDebugRemark(XorStr("inlining failed: too many inlined frames")); return false; } @@ -494,7 +466,7 @@ struct Compiler for (InlineFrame& frame : inlineFrames) if (frame.func == func) { - bytecode.addDebugRemark("inlining failed: can't inline recursive calls"); + bytecode.addDebugRemark(XorStr("inlining failed: can't inline recursive calls")); return false; } @@ -503,7 +475,7 @@ struct Compiler // - 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 if (multRet) { - bytecode.addDebugRemark("inlining failed: can't convert fixed returns to multret"); + bytecode.addDebugRemark(XorStr("inlining failed: can't convert fixed returns to multret")); return false; } @@ -513,7 +485,8 @@ struct Compiler varc[i] = isConstant(expr->args.data[i]); // if the last argument only returns a single value, all following arguments are nil - if (expr->args.size != 0 && !isExprMultRet(expr->args.data[expr->args.size - 1])) + if (expr->args.size != 0 && + !(expr->args.data[expr->args.size - 1]->is() || expr->args.data[expr->args.size - 1]->is())) for (size_t i = expr->args.size; i < func->args.size && i < 8; ++i) varc[i] = true; @@ -526,12 +499,12 @@ struct Compiler if (inlinedCost > threshold) { - bytecode.addDebugRemark("inlining failed: too expensive (cost %d, profit %.2fx)", inlinedCost, double(inlineProfit) / 100); + bytecode.addDebugRemark(XorStr("inlining failed: too expensive (cost %d, profit %.2fx)"), inlinedCost, double(inlineProfit) / 100); return false; } bytecode.addDebugRemark( - "inlining succeeded (cost %d, profit %.2fx, depth %d)", inlinedCost, double(inlineProfit) / 100, int(inlineFrames.size())); + XorStr("inlining succeeded (cost %d, profit %.2fx, depth %d)"), inlinedCost, double(inlineProfit) / 100, int(inlineFrames.size())); compileInlinedCall(expr, func, target, targetCount); return true; @@ -552,7 +525,7 @@ struct Compiler AstLocal* var = func->args.data[i]; AstExpr* arg = i < expr->args.size ? expr->args.data[i] : nullptr; - if (i + 1 == expr->args.size && func->args.size > expr->args.size && isExprMultRet(arg)) + if (i + 1 == expr->args.size && func->args.size > expr->args.size && (arg->is() || arg->is())) { // if the last argument can return multiple values, we need to compute all of them into the remaining arguments unsigned int tail = unsigned(func->args.size - expr->args.size) + 1; @@ -563,7 +536,7 @@ struct Compiler else if (AstExprVarargs* expr = arg->as()) compileExprVarargs(expr, reg, tail); else - LUAU_ASSERT(!"Unexpected expression type"); + lluz_ASSERT(!"Unexpected expression type"); for (size_t j = i; j < func->args.size; ++j) pushLocal(func->args.data[j], uint8_t(reg + (j - i))); @@ -595,7 +568,7 @@ struct Compiler } else { - AstExprLocal* le = FFlag::LuauCompileFreeReassign ? getExprLocal(arg) : arg->as(); + AstExprLocal* le = arg->as(); Variable* lv = le ? variables.find(le->local) : nullptr; // if the argument is a local that isn't mutated, we will simply reuse the existing register @@ -620,7 +593,7 @@ struct Compiler } // fold constant values updated above into expressions in the function body - foldConstants(constants, variables, locstants, builtinsFold, func->body); + foldConstants(constants, variables, locstants, func->body); bool usedFallthrough = false; @@ -661,12 +634,12 @@ struct Compiler if (Constant* var = locstants.find(func->args.data[i])) var->type = Constant::Type_Unknown; - foldConstants(constants, variables, locstants, builtinsFold, func->body); + foldConstants(constants, variables, locstants, func->body); } void compileExprCall(AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop = false, bool multRet = false) { - LUAU_ASSERT(!targetTop || unsigned(target + targetCount) == regTop); + lluz_ASSERT(!targetTop || unsigned(target + targetCount) == regTop); setDebugLine(expr); // normally compileExpr sets up line info, but compileExprCall can be called directly @@ -677,19 +650,19 @@ struct Compiler Function* fi = func ? functions.find(func) : nullptr; if (fi && fi->canInline && - tryCompileInlinedCall(expr, func, target, targetCount, multRet, FInt::LuauCompileInlineThreshold, - FInt::LuauCompileInlineThresholdMaxBoost, FInt::LuauCompileInlineDepth)) + tryCompileInlinedCall(expr, func, target, targetCount, multRet, FInt::LluCompileInlineThreshold, + FInt::LluCompileInlineThresholdMaxBoost, FInt::LluCompileInlineDepth)) return; // add a debug remark for cases when we didn't even call tryCompileInlinedCall if (func && !(fi && fi->canInline)) { if (func->vararg) - bytecode.addDebugRemark("inlining failed: function is variadic"); + bytecode.addDebugRemark(XorStr("inlining failed: function is variadic")); else if (!fi) - bytecode.addDebugRemark("inlining failed: can't inline recursive calls"); + bytecode.addDebugRemark(XorStr("inlining failed: can't inline recursive calls")); else if (getfenvUsed || setfenvUsed) - bytecode.addDebugRemark("inlining failed: module uses getfenv/setfenv"); + bytecode.addDebugRemark(XorStr("inlining failed: module uses getfenv/setfenv")); } } @@ -704,28 +677,34 @@ struct Compiler int bfid = -1; - if (options.optimizationLevel >= 1 && !expr->self) - if (const int* id = builtins.find(expr)) - bfid = *id; + if (options.optimizationLevel >= 1) + { + Builtin builtin = getBuiltin(expr->func, globals, variables); + bfid = getBuiltinFunctionId(builtin, options); + } if (bfid == LBF_SELECT_VARARG) { // Optimization: compile select(_, ...) as FASTCALL1; the builtin will read variadic arguments directly // note: for now we restrict this to single-return expressions since our runtime code doesn't deal with general cases - if (multRet == false && targetCount == 1) + if (multRet == false && targetCount == 1 && expr->args.size == 2 && expr->args.data[1]->is()) return compileExprSelectVararg(expr, target, targetCount, targetTop, multRet, regs); else bfid = -1; } // 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 (!expr->self && bfid >= 0 && expr->args.size >= 1 && expr->args.size <= 2) + { + AstExpr* last = expr->args.data[expr->args.size - 1]; + if (!last->is() && !last->is()) + return compileExprFastcallN(expr, target, targetCount, targetTop, multRet, regs, bfid); + } if (expr->self) { AstExprIndexName* fi = expr->func->as(); - LUAU_ASSERT(fi); + lluz_ASSERT(fi); // Optimization: use local register directly in NAMECALL if possible if (int reg = getExprLocalReg(fi->expr); reg >= 0) @@ -760,14 +739,14 @@ struct Compiler if (expr->self) { AstExprIndexName* fi = expr->func->as(); - LUAU_ASSERT(fi); + lluz_ASSERT(fi); setDebugLine(fi->indexLocation); BytecodeBuilder::StringRef iname = sref(fi->index); int32_t cid = bytecode.addConstantString(iname); if (cid < 0) - CompileError::raise(fi->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(fi->location, XorStr("Exceeded constant limit; simplify the code to compile")); bytecode.emitABC(LOP_NAMECALL, regs, selfreg, uint8_t(BytecodeBuilder::getStringHash(iname))); bytecode.emitAux(cid); @@ -786,7 +765,7 @@ struct Compiler // FASTCALL will skip over the instructions needed to compute function and jump over CALL which must immediately follow the instruction // sequence after FASTCALL if (!bytecode.patchSkipC(fastcallLabel, callLabel)) - CompileError::raise(expr->func->location, "Exceeded jump distance limit; simplify the code to compile"); + CompileError::raise(expr->func->location, XorStr("Exceeded jump distance limit; simplify the code to compile")); } bytecode.emitABC(LOP_CALL, regs, multCall ? 0 : uint8_t(expr->self + expr->args.size + 1), multRet ? 0 : uint8_t(targetCount + 1)); @@ -839,14 +818,14 @@ struct Compiler RegScope rs(this); const Function* f = functions.find(expr); - LUAU_ASSERT(f); + lluz_ASSERT(f); // when the closure has upvalues we'll use this to create the closure at runtime // when the closure has no upvalues, we use constant closures that technically don't rely on the child function list // however, it's still important to add the child function because debugger relies on the function hierarchy when setting breakpoints int16_t pid = bytecode.addChildFunction(f->id); if (pid < 0) - CompileError::raise(expr->location, "Exceeded closure limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded closure limit; simplify the code to compile")); // we use a scratch vector to reduce allocations; this is safe since compileExprFunction is not reentrant captures.clear(); @@ -854,7 +833,7 @@ struct Compiler for (AstLocal* uv : f->upvals) { - LUAU_ASSERT(uv->functionDepth < expr->functionDepth); + lluz_ASSERT(uv->functionDepth < expr->functionDepth); if (int reg = getLocalReg(uv); reg >= 0) { @@ -874,7 +853,7 @@ struct Compiler } else { - LUAU_ASSERT(uv->functionDepth < expr->functionDepth - 1); + lluz_ASSERT(uv->functionDepth < expr->functionDepth - 1); // get upvalue from parent frame // note: this will add uv to the current upvalue list if necessary @@ -906,7 +885,7 @@ struct Compiler bytecode.emitABC(LOP_CAPTURE, uint8_t(c.type), c.data, 0); } - LuauOpcode getUnaryOp(AstExprUnary::Op op) + lluzOpcode getUnaryOp(AstExprUnary::Op op) { switch (op) { @@ -920,12 +899,12 @@ struct Compiler return LOP_LENGTH; default: - LUAU_ASSERT(!"Unexpected unary operation"); + lluz_ASSERT(!"Unexpected unary operation"); return LOP_NOP; } } - LuauOpcode getBinaryOpArith(AstExprBinary::Op op, bool k = false) + lluzOpcode getBinaryOpArith(AstExprBinary::Op op, bool k = false) { switch (op) { @@ -948,12 +927,12 @@ struct Compiler return k ? LOP_POWK : LOP_POW; default: - LUAU_ASSERT(!"Unexpected binary operation"); + lluz_ASSERT(!"Unexpected binary operation"); return LOP_NOP; } } - LuauOpcode getJumpOpCompare(AstExprBinary::Op op, bool not_ = false) + lluzOpcode getJumpOpCompare(AstExprBinary::Op op, bool not_ = false) { switch (op) { @@ -972,7 +951,7 @@ struct Compiler return not_ ? LOP_JUMPIFNOTLE : LOP_JUMPIFLE; default: - LUAU_ASSERT(!"Unexpected binary operation"); + lluz_ASSERT(!"Unexpected binary operation"); return LOP_NOP; } } @@ -1008,7 +987,7 @@ struct Compiler size_t compileCompareJump(AstExprBinary* expr, bool not_ = false) { RegScope rs(this); - LuauOpcode opc = getJumpOpCompare(expr->op, not_); + lluzOpcode opc = getJumpOpCompare(expr->op, not_); bool isEq = (opc == LOP_JUMPIFEQ || opc == LOP_JUMPIFNOTEQ); AstExpr* left = expr->left; @@ -1033,7 +1012,7 @@ struct Compiler opc = LOP_JUMPIFNOTEQK; rr = getConstantIndex(right); - LUAU_ASSERT(rr >= 0); + lluz_ASSERT(rr >= 0); } else rr = compileExprAuto(right, rs); @@ -1062,7 +1041,7 @@ struct Compiler { int cid = bytecode.addConstantNumber(c->valueNumber); if (cid < 0) - CompileError::raise(node->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(node->location, XorStr("Exceeded constant limit; simplify the code to compile")); return cid; } @@ -1098,12 +1077,12 @@ struct Compiler break; default: - LUAU_ASSERT(!"Unexpected constant type"); + lluz_ASSERT(!"Unexpected constant type"); return -1; } if (cid < 0) - CompileError::raise(node->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(node->location, XorStr("Exceeded constant limit; simplify the code to compile")); return cid; } @@ -1419,7 +1398,7 @@ struct Compiler break; default: - LUAU_ASSERT(!"Unexpected binary operation"); + lluz_ASSERT(!"Unexpected binary operation"); } } @@ -1496,7 +1475,7 @@ struct Compiler for (size_t i = 0; i < expr->items.size; ++i) { const AstExprTable::Item& item = expr->items.data[i]; - LUAU_ASSERT(item.key); // no list portion => all items have keys + lluz_ASSERT(item.key); // no list portion => all items have keys const Constant* ckey = constants.find(item.key); @@ -1526,22 +1505,22 @@ struct Compiler for (size_t i = 0; i < expr->items.size; ++i) { const AstExprTable::Item& item = expr->items.data[i]; - LUAU_ASSERT(item.kind == AstExprTable::Item::Record); + lluz_ASSERT(item.kind == AstExprTable::Item::Record); AstExprConstantString* ckey = item.key->as(); - LUAU_ASSERT(ckey); + lluz_ASSERT(ckey); int cid = bytecode.addConstantString(sref(ckey->value)); if (cid < 0) - CompileError::raise(ckey->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(ckey->location, XorStr("Exceeded constant limit; simplify the code to compile")); - LUAU_ASSERT(shape.length < BytecodeBuilder::TableShape::kMaxLength); + lluz_ASSERT(shape.length < BytecodeBuilder::TableShape::kMaxLength); shape.keys[shape.length++] = int16_t(cid); } int32_t tid = bytecode.addConstantTable(shape); if (tid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); if (tid < 32768) { @@ -1560,7 +1539,7 @@ struct Compiler const AstExprTable::Item* last = expr->items.size > 0 ? &expr->items.data[expr->items.size - 1] : nullptr; bool trailingVarargs = last && last->kind == AstExprTable::Item::List && last->value->is(); - LUAU_ASSERT(!trailingVarargs || arraySize > 0); + lluz_ASSERT(!trailingVarargs || arraySize > 0); bytecode.emitABC(LOP_NEWTABLE, reg, uint8_t(encodedHashSize), 0); bytecode.emitAux(arraySize - trailingVarargs + indexSize); @@ -1670,7 +1649,7 @@ struct Compiler int32_t id2 = import2 ? bytecode.addConstantString(sref(import2->index)) : -1; if (id0 < 0 || id1 < 0 || (import2 && id2 < 0)) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); // Note: GETIMPORT encoding is limited to 10 bits per object id component if (id0 < 1024 && id1 < 1024 && id2 < 1024) @@ -1695,7 +1674,7 @@ struct Compiler BytecodeBuilder::StringRef iname = sref(expr->index); int32_t cid = bytecode.addConstantString(iname); if (cid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); bytecode.emitABC(LOP_GETTABLEKS, target, reg, uint8_t(BytecodeBuilder::getStringHash(iname))); bytecode.emitAux(cid); @@ -1722,7 +1701,7 @@ struct Compiler BytecodeBuilder::StringRef iname = sref(cv.getString()); int32_t cid = bytecode.addConstantString(iname); if (cid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); uint8_t rt = compileExprAuto(expr->expr, rs); @@ -1747,7 +1726,7 @@ struct Compiler { int32_t id0 = bytecode.addConstantString(sref(expr->name)); if (id0 < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); // Note: GETIMPORT encoding is limited to 10 bits per object id component if (id0 < 1024) @@ -1767,7 +1746,7 @@ struct Compiler BytecodeBuilder::StringRef gname = sref(expr->name); int32_t cid = bytecode.addConstantString(gname); if (cid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); bytecode.emitABC(LOP_GETGLOBAL, target, 0, uint8_t(BytecodeBuilder::getStringHash(gname))); bytecode.emitAux(cid); @@ -1800,7 +1779,7 @@ struct Compiler // long number encoding: use generic constant path int32_t cid = bytecode.addConstantNumber(d); if (cid < 0) - CompileError::raise(node->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(node->location, XorStr("Exceeded constant limit; simplify the code to compile")); emitLoadK(target, cid); } @@ -1811,14 +1790,14 @@ struct Compiler { int32_t cid = bytecode.addConstantString(sref(cv->getString())); if (cid < 0) - CompileError::raise(node->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(node->location, XorStr("Exceeded constant limit; simplify the code to compile")); emitLoadK(target, cid); } break; default: - LUAU_ASSERT(!"Unexpected constant type"); + lluz_ASSERT(!"Unexpected constant type"); } } @@ -1854,7 +1833,7 @@ struct Compiler { int32_t cid = bytecode.addConstantNumber(expr->value); if (cid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); emitLoadK(target, cid); } @@ -1862,7 +1841,7 @@ struct Compiler { int32_t cid = bytecode.addConstantString(sref(expr->value)); if (cid < 0) - CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(expr->location, XorStr("Exceeded constant limit; simplify the code to compile")); emitLoadK(target, cid); } @@ -1875,7 +1854,7 @@ struct Compiler } else { - LUAU_ASSERT(expr->upvalue); + lluz_ASSERT(expr->upvalue); uint8_t uid = getUpval(expr->local); bytecode.emitABC(LOP_GETUPVAL, target, uid, 0); @@ -1931,7 +1910,7 @@ struct Compiler } else { - LUAU_ASSERT(!"Unknown expression type"); + lluz_ASSERT(!"Unknown expression type"); } } @@ -1962,7 +1941,7 @@ struct Compiler { // we assume that target range is at the top of the register space and can be clobbered // this is what allows us to compile the last call expression - if it's a call - using targetTop=true - LUAU_ASSERT(!targetTop || unsigned(target + targetCount) == regTop); + lluz_ASSERT(!targetTop || unsigned(target + targetCount) == regTop); if (list.size == targetCount) { @@ -2082,7 +2061,7 @@ struct Compiler } else { - LUAU_ASSERT(expr->upvalue); + lluz_ASSERT(expr->upvalue); LValue result = {LValue::Kind_Upvalue}; result.upval = getUpval(expr->local); @@ -2116,7 +2095,7 @@ struct Compiler } else { - LUAU_ASSERT(!"Unknown assignment expression"); + lluz_ASSERT(!"Unknown assignment expression"); return LValue(); } @@ -2143,7 +2122,7 @@ struct Compiler { int32_t cid = bytecode.addConstantString(lv.name); if (cid < 0) - CompileError::raise(lv.location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(lv.location, XorStr("Exceeded constant limit; simplify the code to compile")); bytecode.emitABC(set ? LOP_SETGLOBAL : LOP_GETGLOBAL, reg, 0, uint8_t(BytecodeBuilder::getStringHash(lv.name))); bytecode.emitAux(cid); @@ -2154,7 +2133,7 @@ struct Compiler { int32_t cid = bytecode.addConstantString(lv.name); if (cid < 0) - CompileError::raise(lv.location, "Exceeded constant limit; simplify the code to compile"); + CompileError::raise(lv.location, XorStr("Exceeded constant limit; simplify the code to compile")); bytecode.emitABC(set ? LOP_SETTABLEKS : LOP_GETTABLEKS, reg, lv.reg, uint8_t(BytecodeBuilder::getStringHash(lv.name))); bytecode.emitAux(cid); @@ -2170,7 +2149,7 @@ struct Compiler break; default: - LUAU_ASSERT(!"Unknown lvalue kind"); + lluz_ASSERT(!"Unknown lvalue kind"); } } @@ -2179,27 +2158,19 @@ struct Compiler compileLValueUse(lv, source, /* set= */ true); } - AstExprLocal* getExprLocal(AstExpr* node) - { - if (AstExprLocal* expr = node->as()) - return expr; - else if (AstExprGroup* expr = node->as()) - return getExprLocal(expr->expr); - else if (AstExprTypeAssertion* expr = node->as()) - return getExprLocal(expr->expr); - else - return nullptr; - } - int getExprLocalReg(AstExpr* node) { - if (AstExprLocal* expr = getExprLocal(node)) + if (AstExprLocal* expr = node->as()) { // note: this can't check expr->upvalue because upvalues may be upgraded to locals during inlining Local* l = locals.find(expr->local); return l && l->allocated ? l->reg : -1; } + else if (AstExprGroup* expr = node->as()) + return getExprLocalReg(expr->expr); + else if (AstExprTypeAssertion* expr = node->as()) + return getExprLocalReg(expr->expr); else return -1; } @@ -2485,22 +2456,6 @@ struct Compiler if (options.optimizationLevel >= 1 && options.debugLevel <= 1 && areLocalsRedundant(stat)) return; - // Optimization: for 1-1 local assignments, we can reuse the register *if* neither local is mutated - if (FFlag::LuauCompileFreeReassign && options.optimizationLevel >= 1 && stat->vars.size == 1 && stat->values.size == 1) - { - if (AstExprLocal* re = getExprLocal(stat->values.data[0])) - { - Variable* lv = variables.find(stat->vars.data[0]); - Variable* rv = variables.find(re->local); - - if (int reg = getExprLocalReg(re); reg >= 0 && (!lv || !lv->written) && (!rv || !rv->written)) - { - pushLocal(stat->vars.data[0], uint8_t(reg)); - return; - } - } - } - // note: allocReg in this case allocates into parent block register - note that we don't have RegScope here uint8_t vars = allocReg(stat, unsigned(stat->vars.size)); @@ -2525,24 +2480,24 @@ struct Compiler if (tripCount < 0) { - bytecode.addDebugRemark("loop unroll failed: invalid iteration count"); + bytecode.addDebugRemark(XorStr("loop unroll failed: invalid iteration count")); return false; } if (tripCount > thresholdBase) { - bytecode.addDebugRemark("loop unroll failed: too many iterations (%d)", tripCount); + bytecode.addDebugRemark(XorStr("loop unroll failed: too many iterations (%d)"), tripCount); return false; } if (Variable* lv = variables.find(stat->var); lv && lv->written) { - bytecode.addDebugRemark("loop unroll failed: mutable loop variable"); + bytecode.addDebugRemark(XorStr("loop unroll failed: mutable loop variable")); return false; } AstLocal* var = stat->var; - uint64_t costModel = modelCost(stat->body, &var, 1, builtins); + uint64_t costModel = modelCost(stat->body, &var, 1); // we use a dynamic cost threshold that's based on the fixed limit boosted by the cost advantage we gain due to unrolling bool varc = true; @@ -2555,11 +2510,11 @@ struct Compiler if (unrolledCost > threshold) { bytecode.addDebugRemark( - "loop unroll failed: too expensive (iterations %d, cost %d, profit %.2fx)", tripCount, unrolledCost, double(unrollProfit) / 100); + XorStr("loop unroll failed: too expensive (iterations %d, cost %d, profit %.2fx)"), tripCount, unrolledCost, double(unrollProfit) / 100); return false; } - bytecode.addDebugRemark("loop unroll succeeded (iterations %d, cost %d, profit %.2fx)", tripCount, unrolledCost, double(unrollProfit) / 100); + bytecode.addDebugRemark(XorStr("loop unroll succeeded (iterations %d, cost %d, profit %.2fx)"), tripCount, unrolledCost, double(unrollProfit) / 100); compileUnrolledFor(stat, tripCount, fromc.valueNumber, stepc.valueNumber); return true; @@ -2580,7 +2535,7 @@ struct Compiler locstants[var].type = Constant::Type_Number; locstants[var].valueNumber = from + iv * step; - foldConstants(constants, variables, locstants, builtinsFold, stat); + foldConstants(constants, variables, locstants, stat); size_t iterJumps = loopJumps.size(); @@ -2608,7 +2563,7 @@ struct Compiler // clean up fold state in case we need to recompile - normally we compile the loop body once, but due to inlining we may need to do it again locstants[var].type = Constant::Type_Unknown; - foldConstants(constants, variables, locstants, builtinsFold, stat); + foldConstants(constants, variables, locstants, stat); } void compileStatFor(AstStatFor* stat) @@ -2617,7 +2572,7 @@ struct Compiler // Optimization: small loops can be unrolled when it is profitable if (options.optimizationLevel >= 2 && isConstant(stat->to) && isConstant(stat->from) && (!stat->step || isConstant(stat->step))) - if (tryCompileUnrolledFor(stat, FInt::LuauCompileLoopUnrollThreshold, FInt::LuauCompileLoopUnrollThresholdMaxBoost)) + if (tryCompileUnrolledFor(stat, FInt::LluCompileLoopUnrollThreshold, FInt::LluCompileLoopUnrollThresholdMaxBoost)) return; size_t oldLocals = localStack.size(); @@ -2697,10 +2652,10 @@ struct Compiler // note that we reserve at least 2 variables; this allows our fast path to assume that we need 2 variables instead of 1 or 2 uint8_t vars = allocReg(stat, std::max(unsigned(stat->vars.size), 2u)); - LUAU_ASSERT(vars == regs + 3); + lluz_ASSERT(vars == regs + 3); - LuauOpcode skipOp = LOP_FORGPREP; - LuauOpcode loopOp = LOP_FORGLOOP; + lluzOpcode skipOp = LOP_FORGPREP; + lluzOpcode loopOp = LOP_FORGLOOP; // Optimization: when we iterate via pairs/ipairs, we generate special bytecode that optimizes the traversal using internal iteration index // These instructions dynamically check if generator is equal to next/inext and bail out @@ -2711,12 +2666,12 @@ struct Compiler { Builtin builtin = getBuiltin(stat->values.data[0]->as()->func, globals, variables); - if (builtin.isGlobal("ipairs")) // for .. in ipairs(t) + if (builtin.isGlobal(XorStr("ipairs"))) // for .. in ipairs(t) { skipOp = LOP_FORGPREP_INEXT; - loopOp = FFlag::LuauCompileNoIpairs ? LOP_FORGLOOP : LOP_FORGLOOP_INEXT; + loopOp = FFlag::LluCompileNoIpairs ? LOP_FORGLOOP : LOP_FORGLOOP_INEXT; } - else if (builtin.isGlobal("pairs")) // for .. in pairs(t) + else if (builtin.isGlobal(XorStr("pairs"))) // for .. in pairs(t) { skipOp = LOP_FORGPREP_NEXT; loopOp = LOP_FORGLOOP; @@ -2726,7 +2681,7 @@ struct Compiler { Builtin builtin = getBuiltin(stat->values.data[0], globals, variables); - if (builtin.isGlobal("next")) // for .. in next,t + if (builtin.isGlobal(XorStr("next"))) // for .. in next,t { skipOp = LOP_FORGPREP_NEXT; loopOp = LOP_FORGLOOP; @@ -2758,10 +2713,10 @@ struct Compiler bytecode.emitAD(loopOp, regs, 0); - if (FFlag::LuauCompileNoIpairs) + if (FFlag::LluCompileNoIpairs) { // TODO: remove loopOp as it's a constant now - LUAU_ASSERT(loopOp == LOP_FORGLOOP); + lluz_ASSERT(loopOp == LOP_FORGLOOP); // FORGLOOP uses aux to encode variable count and fast path flag for ipairs traversal in the high bit bytecode.emitAux((skipOp == LOP_FORGPREP_INEXT ? 0x80000000 : 0) | uint32_t(stat->vars.size)); @@ -2940,7 +2895,7 @@ struct Compiler break; default: - LUAU_ASSERT(!"Unexpected compound assignment operation"); + lluz_ASSERT(!"Unexpected compound assignment operation"); } if (var.kind != LValue::Kind_Local) @@ -3001,7 +2956,7 @@ struct Compiler } else if (node->is()) { - LUAU_ASSERT(!loops.empty()); + lluz_ASSERT(!loops.empty()); // before exiting out of the loop, we need to close all local variables that were captured in closures since loop start // normally they are closed by the enclosing blocks, including the loop block, but we're skipping that here @@ -3015,7 +2970,7 @@ struct Compiler } else if (AstStatContinue* stat = node->as()) { - LUAU_ASSERT(!loops.empty()); + lluz_ASSERT(!loops.empty()); if (loops.back().untilCondition) validateContinueUntil(stat, loops.back().untilCondition); @@ -3097,7 +3052,7 @@ struct Compiler } else { - LUAU_ASSERT(!"Unknown statement type"); + lluz_ASSERT(!"Unknown statement type"); } } @@ -3125,13 +3080,13 @@ struct Compiler { if (localStack.size() >= kMaxLocalCount) CompileError::raise( - local->location, "Out of local registers when trying to allocate %s: exceeded limit %d", local->name.value, kMaxLocalCount); + local->location, XorStr("Out of local registers when trying to allocate %s: exceeded limit %d"), local->name.value, kMaxLocalCount); localStack.push_back(local); Local& l = locals[local]; - LUAU_ASSERT(!l.allocated); + lluz_ASSERT(!l.allocated); l.reg = reg; l.allocated = true; @@ -3140,12 +3095,12 @@ struct Compiler bool areLocalsCaptured(size_t start) { - LUAU_ASSERT(start <= localStack.size()); + lluz_ASSERT(start <= localStack.size()); for (size_t i = start; i < localStack.size(); ++i) { Local* l = locals.find(localStack[i]); - LUAU_ASSERT(l); + lluz_ASSERT(l); if (l->captured) return true; @@ -3156,7 +3111,7 @@ struct Compiler void closeLocals(size_t start) { - LUAU_ASSERT(start <= localStack.size()); + lluz_ASSERT(start <= localStack.size()); bool captured = false; uint8_t captureReg = 255; @@ -3164,7 +3119,7 @@ struct Compiler for (size_t i = start; i < localStack.size(); ++i) { Local* l = locals.find(localStack[i]); - LUAU_ASSERT(l); + lluz_ASSERT(l); if (l->captured) { @@ -3181,13 +3136,13 @@ struct Compiler void popLocals(size_t start) { - LUAU_ASSERT(start <= localStack.size()); + lluz_ASSERT(start <= localStack.size()); for (size_t i = start; i < localStack.size(); ++i) { Local* l = locals.find(localStack[i]); - LUAU_ASSERT(l); - LUAU_ASSERT(l->allocated); + lluz_ASSERT(l); + lluz_ASSERT(l->allocated); l->allocated = false; @@ -3205,7 +3160,7 @@ struct Compiler void patchJump(AstNode* node, size_t label, size_t target) { if (!bytecode.patchJumpD(label, target)) - CompileError::raise(node->location, "Exceeded jump distance limit; simplify the code to compile"); + CompileError::raise(node->location, XorStr("Exceeded jump distance limit; simplify the code to compile")); } void patchJumps(AstNode* node, std::vector& labels, size_t target) @@ -3216,7 +3171,7 @@ struct Compiler void patchLoopJumps(AstNode* node, size_t oldJumps, size_t endLabel, size_t contLabel) { - LUAU_ASSERT(oldJumps <= loopJumps.size()); + lluz_ASSERT(oldJumps <= loopJumps.size()); for (size_t i = oldJumps; i < loopJumps.size(); ++i) { @@ -3233,7 +3188,7 @@ struct Compiler break; default: - LUAU_ASSERT(!"Unknown loop jump type"); + lluz_ASSERT(!"Unknown loop jump type"); } } } @@ -3242,7 +3197,7 @@ struct Compiler { unsigned int top = regTop; if (top + count > kMaxRegisterCount) - CompileError::raise(node->location, "Out of registers when trying to allocate %d registers: exceeded limit %d", count, kMaxRegisterCount); + CompileError::raise(node->location, XorStr("Out of registers when trying to allocate %d registers: exceeded limit %d"), count, kMaxRegisterCount); regTop += count; stackSize = std::max(stackSize, regTop); @@ -3253,7 +3208,7 @@ struct Compiler void reserveReg(AstNode* node, unsigned int count) { if (regTop + count > kMaxRegisterCount) - CompileError::raise(node->location, "Out of registers when trying to allocate %d registers: exceeded limit %d", count, kMaxRegisterCount); + CompileError::raise(node->location, XorStr("Out of registers when trying to allocate %d registers: exceeded limit %d"), count, kMaxRegisterCount); stackSize = std::max(stackSize, regTop + count); } @@ -3294,9 +3249,9 @@ struct Compiler bool visit(AstExprGlobal* node) override { - if (node->name == "getfenv") + if (node->name == XorStr("getfenv")) getfenvUsed = true; - if (node->name == "setfenv") + if (node->name == XorStr("setfenv")) setfenvUsed = true; return false; @@ -3354,11 +3309,11 @@ struct Compiler bool visit(AstExprFunction* node) override { const Function* f = self->functions.find(node); - LUAU_ASSERT(f); + lluz_ASSERT(f); for (AstLocal* uv : f->upvals) { - LUAU_ASSERT(uv->functionDepth < node->functionDepth); + lluz_ASSERT(uv->functionDepth < node->functionDepth); if (uv->functionDepth == node->functionDepth - 1) check(uv); @@ -3415,7 +3370,26 @@ struct Compiler bool visit(AstStatReturn* stat) override { - returnsOne &= stat->list.size == 1 && !self->isExprMultRet(stat->list.data[0]); + if (stat->list.size == 1) + { + AstExpr* value = stat->list.data[0]; + + if (AstExprCall* expr = value->as()) + { + AstExprFunction* func = self->getFunctionExpr(expr->func); + Function* fi = func ? self->functions.find(func) : nullptr; + + returnsOne &= fi && fi->returnsOne; + } + else if (value->is()) + { + returnsOne = false; + } + } + else + { + returnsOne = false; + } return false; } @@ -3435,7 +3409,7 @@ struct Compiler : self(self) , oldTop(self->regTop) { - LUAU_ASSERT(top <= self->regTop); + lluz_ASSERT(top <= self->regTop); self->regTop = top; } @@ -3500,7 +3474,7 @@ struct Compiler struct Capture { - LuauCaptureType type; + lluzCaptureType type; uint8_t data; }; @@ -3515,8 +3489,6 @@ struct Compiler DenseHashMap constants; DenseHashMap locstants; DenseHashMap tableShapes; - DenseHashMap builtins; - const DenseHashMap* builtinsFold = nullptr; unsigned int regTop = 0; unsigned int stackSize = 0; @@ -3532,20 +3504,9 @@ struct Compiler std::vector captures; }; -void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, const AstNameTable& names, const CompileOptions& inputOptions) +void compileOrThrow(BytecodeBuilder& bytecode, AstStatBlock* root, const AstNameTable& names, const CompileOptions& options) { - LUAU_TIMETRACE_SCOPE("compileOrThrow", "Compiler"); - - LUAU_ASSERT(parseResult.root); - LUAU_ASSERT(parseResult.errors.empty()); - - CompileOptions options = inputOptions; - - for (const HotComment& hc : parseResult.hotcomments) - if (hc.header && hc.content.compare(0, 9, "optimize ") == 0) - options.optimizationLevel = std::max(0, std::min(2, atoi(hc.content.c_str() + 9))); - - AstStatBlock* root = parseResult.root; + lluz_TIMETRACE_SCOPE(XorStr("compileOrThrow", "Compiler")); Compiler compiler(bytecode, options); @@ -3555,24 +3516,17 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c // this pass analyzes mutability of locals/globals and associates locals with their initial values trackValues(compiler.globals, compiler.variables, root); - // builtin folding is enabled on optimization level 2 since we can't deoptimize folding at runtime - if (options.optimizationLevel >= 2) - compiler.builtinsFold = &compiler.builtins; - if (options.optimizationLevel >= 1) { - // this pass tracks which calls are builtins and can be compiled more efficiently - analyzeBuiltins(compiler.builtins, compiler.globals, compiler.variables, options, root); - // this pass analyzes constantness of expressions - foldConstants(compiler.constants, compiler.variables, compiler.locstants, compiler.builtinsFold, root); + foldConstants(compiler.constants, compiler.variables, compiler.locstants, root); // this pass analyzes table assignments to estimate table shapes for initially empty tables predictTableShapes(compiler.tableShapes, root); } // this visitor tracks calls to getfenv/setfenv and disables some optimizations when they are found - if (options.optimizationLevel >= 1 && (names.get("getfenv").value || names.get("setfenv").value)) + if (options.optimizationLevel >= 1 && (names.get(XorStr("getfenv")).value || names.get(XorStr("setfenv")).value)) { Compiler::FenvVisitor fenvVisitor(compiler.getfenvUsed, compiler.setfenvUsed); root->visit(&fenvVisitor); @@ -3588,11 +3542,11 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c compiler.compileFunction(expr); AstExprFunction main(root->location, /*generics= */ AstArray(), /*genericPacks= */ AstArray(), - /* self= */ nullptr, AstArray(), /* vararg= */ Luau::Location(), root, /* functionDepth= */ 0, /* debugname= */ AstName()); + /* self= */ nullptr, AstArray(), /* vararg= */ lluz::Location(), root, /* functionDepth= */ 0, /* debugname= */ AstName()); uint32_t mainid = compiler.compileFunction(&main); const Compiler::Function* mainf = compiler.functions.find(&main); - LUAU_ASSERT(mainf && mainf->upvals.empty()); + lluz_ASSERT(mainf && mainf->upvals.empty()); bytecode.setMainFunction(mainid); bytecode.finalize(); @@ -3607,12 +3561,14 @@ void compileOrThrow(BytecodeBuilder& bytecode, const std::string& source, const if (!result.errors.empty()) throw ParseErrors(result.errors); - compileOrThrow(bytecode, result, names, options); + AstStatBlock* root = result.root; + + compileOrThrow(bytecode, root, names, options); } std::string compile(const std::string& source, const CompileOptions& options, const ParseOptions& parseOptions, BytecodeEncoder* encoder) { - LUAU_TIMETRACE_SCOPE("compile", "Compiler"); + lluz_TIMETRACE_SCOPE(XorStr("compile", "Compiler")); Allocator allocator; AstNameTable names(allocator); @@ -3621,8 +3577,8 @@ std::string compile(const std::string& source, const CompileOptions& options, co if (!result.errors.empty()) { // Users of this function expect only a single error message - const Luau::ParseError& parseError = result.errors.front(); - std::string error = format(":%d: %s", parseError.getLocation().begin.line + 1, parseError.what()); + const lluz::ParseError& parseError = result.errors.front(); + std::string error = format(XorStr(":%d: %s"), parseError.getLocation().begin.line + 1, parseError.what()); return BytecodeBuilder::getError(error); } @@ -3630,15 +3586,15 @@ std::string compile(const std::string& source, const CompileOptions& options, co try { BytecodeBuilder bcb(encoder); - compileOrThrow(bcb, result, names, options); + compileOrThrow(bcb, result.root, names, options); return bcb.getBytecode(); } catch (CompileError& e) { - std::string error = format(":%d: %s", e.getLocation().begin.line + 1, e.what()); + std::string error = format(XorStr(":%d: %s"), e.getLocation().begin.line + 1, e.what()); return BytecodeBuilder::getError(error); } } -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/ConstantFolding.cpp b/Compiler/src/ConstantFolding.cpp index 34f79544..4695818c 100644 --- a/Compiler/src/ConstantFolding.cpp +++ b/Compiler/src/ConstantFolding.cpp @@ -1,18 +1,18 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "ConstantFolding.h" -#include "BuiltinFolding.h" +#include "..\..\..\..\Security\XorString.h" #include -namespace Luau +namespace lluz { namespace Compile { static bool constantsEqual(const Constant& la, const Constant& ra) { - LUAU_ASSERT(la.type != Constant::Type_Unknown && ra.type != Constant::Type_Unknown); + lluz_ASSERT(la.type != Constant::Type_Unknown && ra.type != Constant::Type_Unknown); switch (la.type) { @@ -29,7 +29,7 @@ static bool constantsEqual(const Constant& la, const Constant& ra) return ra.type == Constant::Type_String && la.stringLength == ra.stringLength && memcmp(la.valueString, ra.valueString, la.stringLength) == 0; default: - LUAU_ASSERT(!"Unexpected constant type in comparison"); + lluz_ASSERT(!"Unexpected constant type in comparison"); return false; } } @@ -63,7 +63,7 @@ static void foldUnary(Constant& result, AstExprUnary::Op op, const Constant& arg break; default: - LUAU_ASSERT(!"Unexpected unary operation"); + lluz_ASSERT(!"Unexpected unary operation"); } } @@ -185,7 +185,7 @@ static void foldBinary(Constant& result, AstExprBinary::Op op, const Constant& l break; default: - LUAU_ASSERT(!"Unexpected binary operation"); + lluz_ASSERT(!"Unexpected binary operation"); } } @@ -195,18 +195,13 @@ struct ConstantVisitor : AstVisitor DenseHashMap& variables; DenseHashMap& locals; - const DenseHashMap* builtins; - bool wasEmpty = false; - std::vector builtinArgs; - - ConstantVisitor(DenseHashMap& constants, DenseHashMap& variables, - DenseHashMap& locals, const DenseHashMap* builtins) + ConstantVisitor( + DenseHashMap& constants, DenseHashMap& variables, DenseHashMap& locals) : constants(constants) , variables(variables) , locals(locals) - , builtins(builtins) { // since we do a single pass over the tree, if the initial state was empty we don't need to clear out old entries wasEmpty = constants.empty() && locals.empty(); @@ -260,37 +255,8 @@ struct ConstantVisitor : AstVisitor { analyze(expr->func); - if (const int* bfid = builtins ? builtins->find(expr) : nullptr) - { - // since recursive calls to analyze() may reuse the vector we need to be careful and preserve existing contents - size_t offset = builtinArgs.size(); - bool canFold = true; - - builtinArgs.reserve(offset + expr->args.size); - - for (size_t i = 0; i < expr->args.size; ++i) - { - Constant ac = analyze(expr->args.data[i]); - - if (ac.type == Constant::Type_Unknown) - canFold = false; - else - builtinArgs.push_back(ac); - } - - if (canFold) - { - LUAU_ASSERT(builtinArgs.size() == offset + expr->args.size); - result = foldBuiltin(*bfid, builtinArgs.data() + offset, expr->args.size); - } - - builtinArgs.resize(offset); - } - else - { - for (size_t i = 0; i < expr->args.size; ++i) - analyze(expr->args.data[i]); - } + for (size_t i = 0; i < expr->args.size; ++i) + analyze(expr->args.data[i]); } else if (AstExprIndexName* expr = node->as()) { @@ -351,7 +317,7 @@ struct ConstantVisitor : AstVisitor } else { - LUAU_ASSERT(!"Unknown expression type"); + lluz_ASSERT(!"Unknown expression type"); } recordConstant(constants, node, result); @@ -374,7 +340,7 @@ struct ConstantVisitor : AstVisitor { // note: we rely on trackValues to have been run before us Variable* v = variables.find(local); - LUAU_ASSERT(v); + lluz_ASSERT(v); if (!v->written) { @@ -431,11 +397,11 @@ struct ConstantVisitor : AstVisitor }; void foldConstants(DenseHashMap& constants, DenseHashMap& variables, - DenseHashMap& locals, const DenseHashMap* builtins, AstNode* root) + DenseHashMap& locals, AstNode* root) { - ConstantVisitor visitor{constants, variables, locals, builtins}; + ConstantVisitor visitor{constants, variables, locals}; root->visit(&visitor); } } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/ConstantFolding.h b/Compiler/src/ConstantFolding.h index d67d9285..3b22b396 100644 --- a/Compiler/src/ConstantFolding.h +++ b/Compiler/src/ConstantFolding.h @@ -1,9 +1,9 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "ValueTracking.h" -namespace Luau +namespace lluz { namespace Compile { @@ -26,24 +26,24 @@ struct Constant { bool valueBoolean; double valueNumber; - const char* valueString = nullptr; // length stored in stringLength + char* valueString = nullptr; // length stored in stringLength }; bool isTruthful() const { - LUAU_ASSERT(type != Type_Unknown); + lluz_ASSERT(type != Type_Unknown); return type != Type_Nil && !(type == Type_Boolean && valueBoolean == false); } - AstArray getString() const + AstArray getString() const { - LUAU_ASSERT(type == Type_String); + lluz_ASSERT(type == Type_String); return {valueString, stringLength}; } }; void foldConstants(DenseHashMap& constants, DenseHashMap& variables, - DenseHashMap& locals, const DenseHashMap* builtins, AstNode* root); + DenseHashMap& locals, AstNode* root); } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/CostModel.cpp b/Compiler/src/CostModel.cpp index 81cbfd7a..9273bbb8 100644 --- a/Compiler/src/CostModel.cpp +++ b/Compiler/src/CostModel.cpp @@ -1,12 +1,14 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "CostModel.h" -#include "Luau/Common.h" -#include "Luau/DenseHash.h" +#include "lluz/Common.h" +#include "lluz/DenseHash.h" + +#include "..\..\..\..\Security\XorString.h" #include -namespace Luau +namespace lluz { namespace Compile { @@ -113,14 +115,11 @@ struct Cost struct CostVisitor : AstVisitor { - const DenseHashMap& builtins; - DenseHashMap vars; Cost result; - CostVisitor(const DenseHashMap& builtins) - : builtins(builtins) - , vars(nullptr) + CostVisitor() + : vars(nullptr) { } @@ -151,21 +150,14 @@ struct CostVisitor : AstVisitor } else if (AstExprCall* expr = node->as()) { - // builtin cost modeling is different from regular calls because we use FASTCALL to compile these - // thus we use a cheaper baseline, don't account for function, and assume constant/local copy is free - bool builtin = builtins.find(expr) != nullptr; - bool builtinShort = builtin && expr->args.size <= 2; // FASTCALL1/2 - - Cost cost = builtin ? 2 : 3; - - if (!builtin) - cost += model(expr->func); + Cost cost = 3; + cost += model(expr->func); for (size_t i = 0; i < expr->args.size; ++i) { Cost ac = model(expr->args.data[i]); // for constants/locals we still need to copy them to the argument list - cost += ac.model == 0 && !builtinShort ? Cost(1) : ac; + cost += ac.model == 0 ? Cost(1) : ac; } return cost; @@ -217,7 +209,7 @@ struct CostVisitor : AstVisitor } else { - LUAU_ASSERT(!"Unknown expression type"); + lluz_ASSERT(!"Unknown expression type"); return {}; } } @@ -337,9 +329,9 @@ struct CostVisitor : AstVisitor } }; -uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount, const DenseHashMap& builtins) +uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount) { - CostVisitor visitor{builtins}; + CostVisitor visitor; for (size_t i = 0; i < varCount && i < 7; ++i) visitor.vars[vars[i]] = 0xffull << (i * 8 + 8); @@ -379,4 +371,4 @@ int getTripCount(double from, double to, double step) } } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/CostModel.h b/Compiler/src/CostModel.h index e8f3e166..91d9bb3f 100644 --- a/Compiler/src/CostModel.h +++ b/Compiler/src/CostModel.h @@ -1,16 +1,15 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once -#include "Luau/Ast.h" -#include "Luau/DenseHash.h" +#include "lluz/Ast.h" -namespace Luau +namespace lluz { namespace Compile { // cost model: 8 bytes, where first byte is the baseline cost, and the next 7 bytes are discounts for when variable #i is constant -uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount, const DenseHashMap& builtins); +uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount); // cost is computed as B - sum(Di * Ci), where B is baseline cost, Di is the discount for each variable and Ci is 1 when variable #i is constant int computeCost(uint64_t model, const bool* varsConst, size_t varCount); @@ -19,4 +18,4 @@ int computeCost(uint64_t model, const bool* varsConst, size_t varCount); int getTripCount(double from, double to, double step); } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/TableShape.cpp b/Compiler/src/TableShape.cpp index 5a866e87..f989bee2 100644 --- a/Compiler/src/TableShape.cpp +++ b/Compiler/src/TableShape.cpp @@ -1,7 +1,9 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "TableShape.h" -namespace Luau +#include "..\..\..\..\Security\XorString.h" + +namespace lluz { namespace Compile { @@ -17,7 +19,7 @@ static AstExprTable* getTableHint(AstExpr* expr) // setmetatable(table literal, ...) if (AstExprCall* call = expr->as(); call && !call->self && call->args.size == 2) - if (AstExprGlobal* func = call->func->as(); func && func->name == "setmetatable") + if (AstExprGlobal* func = call->func->as(); func && func->name == XorStr("setmetatable")) if (AstExprTable* table = call->args.data[0]->as()) return table; @@ -155,4 +157,4 @@ void predictTableShapes(DenseHashMap& shapes, AstNode } } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/TableShape.h b/Compiler/src/TableShape.h index f30853a7..6e9efc69 100644 --- a/Compiler/src/TableShape.h +++ b/Compiler/src/TableShape.h @@ -1,10 +1,10 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once -#include "Luau/Ast.h" -#include "Luau/DenseHash.h" +#include "lluz/Ast.h" +#include "lluz/DenseHash.h" -namespace Luau +namespace lluz { namespace Compile { @@ -18,4 +18,4 @@ struct TableShape void predictTableShapes(DenseHashMap& shapes, AstNode* root); } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/ValueTracking.cpp b/Compiler/src/ValueTracking.cpp index 0bfaf9b3..2ebc01ed 100644 --- a/Compiler/src/ValueTracking.cpp +++ b/Compiler/src/ValueTracking.cpp @@ -1,9 +1,11 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "ValueTracking.h" -#include "Luau/Lexer.h" +#include "lluz/Lexer.h" -namespace Luau +#include "..\..\..\..\Security\XorString.h" + +namespace lluz { namespace Compile { @@ -84,7 +86,7 @@ struct ValueVisitor : AstVisitor void assignMutable(DenseHashMap& globals, const AstNameTable& names, const char** mutableGlobals) { - if (AstName name = names.get("_G"); name.value) + if (AstName name = names.get(XorStr("_G")); name.value) globals[name] = Global::Mutable; if (mutableGlobals) @@ -100,4 +102,4 @@ void trackValues(DenseHashMap& globals, DenseHashMap& globals, AstNa } } // namespace Compile -} // namespace Luau +} // namespace lluz diff --git a/Compiler/src/lcode.cpp b/Compiler/src/lcode.cpp index ee150b17..148b3615 100644 --- a/Compiler/src/lcode.cpp +++ b/Compiler/src/lcode.cpp @@ -1,19 +1,19 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details #include "luacode.h" -#include "Luau/Compiler.h" +#include "lluz/Compiler.h" #include -char* luau_compile(const char* source, size_t size, lua_CompileOptions* options, size_t* outsize) +char* lluz_compile(const char* source, size_t size, lua_CompileOptions* options, size_t* outsize) { - LUAU_ASSERT(outsize); + lluz_ASSERT(outsize); - Luau::CompileOptions opts; + lluz::CompileOptions opts; if (options) { - static_assert(sizeof(lua_CompileOptions) == sizeof(Luau::CompileOptions), "C and C++ interface must match"); + static_assert(sizeof(lua_CompileOptions) == sizeof(lluz::CompileOptions), "C and C++ interface must match"); memcpy(static_cast(&opts), options, sizeof(opts)); }