diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 65aeddd..ecff380 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ jobs: runs-on: windows-2019 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive @@ -23,13 +23,13 @@ jobs: run: build.bat - name: Upload module dll - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: bytecode-module-windows-dll path: ./BUILD/bin/module/js-bytecode-module.dll - name: Upload module pdb - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: bytecode-module-windows-pdb path: ./BUILD/bin/module/js-bytecode-module.pdb @@ -37,25 +37,19 @@ jobs: build-linux: name: Build linux - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive - - name: Install Clang - run: | - sudo apt update - sudo apt install clang-6.0 - - name: Build run: | - export CXX=/usr/bin/clang++-6.0 ./build.sh - name: Upload module so - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: bytecode-module-linux-so path: ./BUILD/module/libjs-bytecode-module.so @@ -66,19 +60,19 @@ jobs: needs: [build-linux, build-windows] steps: - name: Download windows module dll - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: bytecode-module-windows-dll path: dist-windows/modules - name: Download windows module pdb - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: bytecode-module-windows-pdb path: dist - name: Download linux module so - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: bytecode-module-linux-so path: dist-linux/modules diff --git a/.gitmodules b/.gitmodules index 6f484f9..895db82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "module/deps/cpp-sdk"] path = module/deps/cpp-sdk - url = https://github.com/altmp/cpp-sdk.git -[submodule "executable/deps/alt-config"] - path = executable/deps/alt-config - url = git@github.com:altmp/alt-config.git + url = https://github.com/altmp/cpp-sdk.git \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 1bea313..3afb888 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -15,7 +15,7 @@ ], "windowsSdkVersion": "10.0.19041.0", "cStandard": "c11", - "cppStandard": "c++17", + "cppStandard": "c++20", "intelliSenseMode": "msvc-x64", "configurationProvider": "ms-vscode.cmake-tools" } diff --git a/CMakeLists.txt b/CMakeLists.txt index f66ca13..f40a0e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required (VERSION 3.10) project("js-bytecode") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 0389e56..7f9960d 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -12,8 +12,6 @@ add_library(${PROJECT_NAME} STATIC "compiler.cpp") if(UNIX) target_compile_options(${PROJECT_NAME} PRIVATE - -std=c++17 - -stdlib=libstdc++ -fPIC ) endif() diff --git a/compiler/compiler.cpp b/compiler/compiler.cpp index 058bccb..c60223c 100644 --- a/compiler/compiler.cpp +++ b/compiler/compiler.cpp @@ -49,7 +49,7 @@ bool Compiler::CompileModule(const std::string& fileName, bool compileDependenci } // Write the bytecode to file - std::vector bytecodeResult = CreateBytecodeBuffer(cache->data, cache->length); + std::vector bytecodeResult = CreateBytecodeBuffer(cache->data, cache->length, sourceCode.size()); bool writeResult = package->WriteFile(fileName, (void*)bytecodeResult.data(), bytecodeResult.size()); if(!writeResult) { @@ -85,8 +85,13 @@ bool Compiler::CompileModule(const std::string& fileName, bool compileDependenci // Compile the dependency file std::string fullFileName = package->ResolveFile(depPath, fileName); + // Check if the file has already been compiled if(std::find(compiledFiles.begin(), compiledFiles.end(), fullFileName) != compiledFiles.end()) continue; + + // Dont compile if the module is ignored + if(std::find(ignoredModules.begin(), ignoredModules.end(), fullFileName) != ignoredModules.end()) continue; + if(!CompileModule(fullFileName, true)) return false; } } @@ -101,35 +106,34 @@ bool Compiler::IsBytecodeFile(void* buffer, size_t size) return true; } -std::vector Compiler::CreateBytecodeBuffer(const uint8_t* buffer, int length) +std::vector Compiler::CreateBytecodeBuffer(const uint8_t* buffer, int length, int sourceLength) { // Make necessary changes to the bytecode - FixBytecode(buffer); + FixBytecode(buffer, sourceLength); // Create our own custom bytecode buffer by appending our magic bytes // at the front, and then the bytecode itself at the end std::vector buf; - size_t bufSize = magicBytes.size() + length; + size_t bufSize = magicBytes.size() + sizeof(int) + length; buf.resize(bufSize); memcpy(buf.data(), magicBytes.data(), magicBytes.size()); - memcpy(buf.data() + magicBytes.size(), buffer, length); + memcpy(buf.data() + magicBytes.size(), &sourceLength, sizeof(int)); + memcpy(buf.data() + magicBytes.size() + sizeof(int), buffer, length); - return std::move(buf); + return buf; } -// Hash for empty module ("") -static constexpr uint32_t srcHash = 2147483648; static constexpr int srcHashOffset = 8; static constexpr uint32_t flagsHash = 3901848073; static constexpr int flagsHashOffset = 12; -void Compiler::FixBytecode(const uint8_t* buffer) +void Compiler::FixBytecode(const uint8_t* buffer, int sourceLength) { - // Copy hash of empty source file into bytecode source hash section + // Copy hash of source into bytecode source hash section // Needed because V8 compares the bytecode code hash to provided source hash - Helpers::CopyValueToBuffer(buffer, srcHashOffset, srcHash); + Helpers::CopyValueToBuffer(buffer, srcHashOffset, Helpers::CreateV8SourceHash(sourceLength)); // Overwrite flags hash with the hash used in client js // !!! Make sure to update the hash if flags in client js change !!! diff --git a/compiler/compiler.h b/compiler/compiler.h index 9001773..69ddd90 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -73,8 +73,8 @@ namespace BytecodeCompiler bool IsBytecodeFile(void* buffer, size_t size); private: - std::vector CreateBytecodeBuffer(const uint8_t* buffer, int length); + std::vector CreateBytecodeBuffer(const uint8_t* buffer, int length, int sourceLength); - static void FixBytecode(const uint8_t* buffer); + static void FixBytecode(const uint8_t* buffer, int sourceLength); }; } // namespace BytecodeCompiler diff --git a/compiler/helpers.h b/compiler/helpers.h index 6e46eb9..f477b9e 100644 --- a/compiler/helpers.h +++ b/compiler/helpers.h @@ -28,6 +28,13 @@ namespace Helpers } } } + // Copies 'SerializedCodeData::SourceHash' behaviour + inline uint32_t CreateV8SourceHash(uint32_t sourceSize) + { + // We always use modules, so this flag is always used + static constexpr uint32_t moduleFlagMask = (1 << 31); + return sourceSize | moduleFlagMask; + } inline void CheckTryCatch(const std::string& fileName, BytecodeCompiler::ILogger* logger, v8::TryCatch& tryCatch, v8::Local ctx) { if(tryCatch.HasCaught()) diff --git a/docs/internal.md b/docs/internal.md index c167ec0..5c280eb 100644 --- a/docs/internal.md +++ b/docs/internal.md @@ -50,5 +50,7 @@ so that the module is working again. ## Format The bytecode we send to the client has exactly *5 bytes* of magic bytes at the front, these bytes are `ALTBC` to identify the data as alt:V bytecode, when we write it to file. -To read this bytecode, we need to check for these 5 magic bytes at the front, if they match, remove them from the buffer, +After that there are *4 bytes* that form a 4-byte integer that corresponds to the size of the original source code (this is needed because V8 sometimes uses the source code buffer, +when compiling functions, and if the buffer is too small, it crashes) that will be used to create a string to pass to the script compiler with the length of the original source code. +To read this bytecode, we need to check for these 5 magic bytes at the front, if they match, remove them and the 4 bytes from the source code length from the buffer, and the remaining buffer is the full bytecode generated by V8, which we can then use to instantiate the script. diff --git a/executable/CMakeLists.txt b/executable/CMakeLists.txt index 42311fc..928ab50 100644 --- a/executable/CMakeLists.txt +++ b/executable/CMakeLists.txt @@ -16,6 +16,12 @@ add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_FILES} ) +if(UNIX) + target_compile_options(${PROJECT_NAME} PRIVATE + -fPIC + ) +endif() + include(Shared) SetupProject("executable") @@ -27,10 +33,6 @@ if(WIN32) ${GLOBAL_DEPS_FOLDER}/v8/lib/$,Debug,Release>/v8_monolith.lib ) elseif(UNIX) - target_compile_options(${PROJECT_NAME} PRIVATE - -std=c++17 - -stdlib=libstdc++ - ) set(LINK_LIBS ${GLOBAL_DEPS_FOLDER}/v8/lib/$,Debug,Release>/libv8_monolith.a ) diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index b2a46e6..4212f62 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -20,6 +20,12 @@ add_library(${PROJECT_NAME} SHARED ${PROJECT_SOURCE_FILES} ) +if(UNIX) + target_compile_options(${PROJECT_NAME} PRIVATE + -fPIC + ) +endif() + add_dependencies(${PROJECT_NAME} alt-sdk) include(Shared) @@ -42,13 +48,6 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE ${ALTV_JS_DEFS} ) -if(UNIX) - target_compile_options(${PROJECT_NAME} PRIVATE - -std=c++17 - -stdlib=libstdc++ - ) -endif() - if(WIN32) set(ALTV_JS_LINKS # Platform binaries diff --git a/module/deps/Log.h b/module/deps/Log.h index c0b11fb..5bf72e5 100644 --- a/module/deps/Log.h +++ b/module/deps/Log.h @@ -32,13 +32,13 @@ class Log buf << val; return *this; } -#if _HAS_CXX20 +#if __cplusplus >= 202002L Log& Put(const char8_t* val) { buf << (const char*)val; return *this; } -#endif // _HAS_CXX20 +#endif // __cplusplus Log& Put(LogFn val) { return val(*this); diff --git a/module/deps/cpp-sdk b/module/deps/cpp-sdk index b273181..61022fa 160000 --- a/module/deps/cpp-sdk +++ b/module/deps/cpp-sdk @@ -1 +1 @@ -Subproject commit b273181c402de4617841eb19f69d6e8ad39253da +Subproject commit 61022fa57f5973d79f61a2c2e6e784521e4b7263 diff --git a/module/src/main.cpp b/module/src/main.cpp index 1348539..d69cdb0 100644 --- a/module/src/main.cpp +++ b/module/src/main.cpp @@ -13,10 +13,12 @@ static void CommandHandler(const std::vector& args) else if(args[0] == "--version") { Log::Colored << "~ly~cpp-sdk: #" << ALT_SDK_VERSION << Log::Endl; - Log::Colored << "~ly~" << u8"Copyright © 2022 altMP team." << Log::Endl; + Log::Colored << "~ly~" + << "Copyright | 2022 altMP team." << Log::Endl; Log::Colored << "~ly~v8: " << v8::V8::GetVersion() << Log::Endl; - Log::Colored << "~ly~" << u8"Copyright © 2014 The V8 project authors." << Log::Endl; + Log::Colored << "~ly~" + << "Copyright | 2014 The V8 project authors." << Log::Endl; } else if(args[0] == "--help") { diff --git a/module/src/runtime.cpp b/module/src/runtime.cpp index 6c20cb6..0ce74e4 100644 --- a/module/src/runtime.cpp +++ b/module/src/runtime.cpp @@ -27,7 +27,19 @@ void JSBytecodeRuntime::ProcessClientFile(alt::IResource* resource, alt::IPackag Logger compilerLogger; BytecodeCompiler::Compiler compiler(isolate, &compilerPackage, &compilerLogger); - static std::vector ignoredModules = { "alt", "alt-client", "natives", "alt-worker", "alt-shared" }; + Config::Value::ValuePtr config = resource->GetConfig(); + // Get ignored files + std::vector ignoredModules = { "alt", "alt-client", "natives", "alt-worker", "alt-shared" }; + Config::Value::ValuePtr ignoredFiles = config->Get("ignored-files"); + if(ignoredFiles->IsList()) + { + Config::Value::List list = ignoredFiles->As(); + ignoredModules.reserve(ignoredModules.size() + list.size()); + for(auto& item : list) + { + if(item->IsString()) ignoredModules.push_back(item->As()); + } + } compiler.SetIgnoredModules(ignoredModules); // Compile client main file @@ -35,16 +47,15 @@ void JSBytecodeRuntime::ProcessClientFile(alt::IResource* resource, alt::IPackag if(!result) return; // Compile the extra files - alt::config::Node config = resource->GetConfig(); - alt::config::Node& node = config["extra-compile-files"]; - if(node && node.IsList()) + Config::Value::ValuePtr extraCompileFiles = config->Get("extra-compile-files"); + if(extraCompileFiles->IsList()) { - alt::config::Node::List& list = node.ToList(); + Config::Value::List list = extraCompileFiles->As(); std::vector extraFilePatterns; extraFilePatterns.reserve(list.size()); - for(alt::config::Node& item : list) + for(auto& item : list) { - if(item.IsScalar()) extraFilePatterns.push_back(item.ToString()); + if(item->IsString()) extraFilePatterns.push_back(item->As()); } std::set files = resource->GetMatchedFiles(extraFilePatterns);