From f6844f5413cf3404244428c2c1c39f899275b660 Mon Sep 17 00:00:00 2001 From: LeonMrBonnie Date: Sat, 13 May 2023 15:15:20 +0200 Subject: [PATCH] Revert "compiler: Remove source length from buffer" This reverts commit 19dc4fa81e041be6ab60c8179b7e4c1b43e9c77a. --- compiler/compiler.cpp | 291 +++++++++++++++++++++--------------------- compiler/compiler.h | 4 +- 2 files changed, 148 insertions(+), 147 deletions(-) diff --git a/compiler/compiler.cpp b/compiler/compiler.cpp index 6fd9af9..7a4c444 100644 --- a/compiler/compiler.cpp +++ b/compiler/compiler.cpp @@ -1,145 +1,146 @@ -#include "compiler.h" -#include "helpers.h" - -#include - -using namespace BytecodeCompiler; - -bool Compiler::CompileModule(const std::string& fileName, bool compileDependencies) -{ - // Read the file - if(!package->FileExists(fileName)) - { - logger->LogError("File not found: " + fileName); - return false; - } - size_t size = package->GetFileSize(fileName); - std::string sourceCode; - sourceCode.resize(size); - if(!package->ReadFile(fileName, sourceCode.data(), sourceCode.size())) - { - logger->LogError("Failed to read file: " + fileName); - return false; - } - - v8::TryCatch tryCatch(isolate); - v8::Local ctx = v8::Context::New(isolate); - v8::Context::Scope ctxScope(ctx); - - // Compile the file to a JavaScript module - v8::ScriptOrigin origin( - isolate, v8::String::NewFromUtf8(isolate, fileName.c_str()).ToLocalChecked(), 0, 0, false, -1, v8::Local(), false, false, true, v8::Local()); - v8::ScriptCompiler::Source source(v8::String::NewFromUtf8(isolate, sourceCode.c_str()).ToLocalChecked(), origin); - v8::MaybeLocal maybeModule = v8::ScriptCompiler::CompileModule(isolate, &source); - if(maybeModule.IsEmpty() || tryCatch.HasCaught()) - { - logger->LogError("Failed to compile module: " + fileName); - Helpers::CheckTryCatch(fileName, logger, tryCatch, ctx); - return false; - } - - // Retrieve the bytecode from the module - v8::Local module = maybeModule.ToLocalChecked(); - v8::ScriptCompiler::CachedData* cache = v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()); - if(cache == nullptr || tryCatch.HasCaught()) - { - logger->LogError("Failed to create bytecode: " + fileName); - Helpers::CheckTryCatch(fileName, logger, tryCatch, ctx); - return false; - } - - // Write the bytecode to file - std::vector bytecodeResult = CreateBytecodeBuffer(cache->data, cache->length); - bool writeResult = package->WriteFile(fileName, (void*)bytecodeResult.data(), bytecodeResult.size()); - if(!writeResult) - { - logger->LogError("Failed to write to file: " + fileName); - return false; - } - - // Make sure the byte buffer is deleted with the cached data from V8 - cache->buffer_policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferOwned; - delete cache; - - logger->Log("Converted file to bytecode: " + logger->GetHighlightColor() + fileName); - compiledFiles.push_back(fileName); - - // Compile all dependencies - if(compileDependencies) - { - v8::Local ctx = v8::Context::New(isolate); - v8::Local dependencies = module->GetModuleRequests(); - int length = dependencies->Length(); - for(int i = 0; i < length; i++) - { - v8::Local dep = dependencies->Get(ctx, i); - v8::Local request = dep.As(); - // Ignore all imports with import assertions, as those are not loaded as - // normal JS files - if(request->GetImportAssertions()->Length() > 0) continue; - - v8::Local depStr = request->GetSpecifier(); - std::string depPath = *v8::String::Utf8Value(isolate, depStr); - // Ignore the built-in modules - if(std::find(ignoredModules.begin(), ignoredModules.end(), depPath) != ignoredModules.end()) continue; - - // Compile the dependency file - std::string fullFileName = package->ResolveFile(depPath, fileName); - if(!package->FileExists(fullFileName)) - { - logger->LogError("File not found: " + depPath); - return false; - } - - // 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; - } - } - - return true; -} - -bool Compiler::IsBytecodeFile(void* buffer, size_t size) -{ - if(size < magicBytes.size()) return false; - if(memcmp(buffer, magicBytes.data(), magicBytes.size()) != 0) return false; - return true; -} - -std::vector Compiler::CreateBytecodeBuffer(const uint8_t* buffer, int length) -{ - // Make necessary changes to the bytecode - FixBytecode(buffer); - - // 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; - buf.resize(bufSize); - - memcpy(buf.data(), magicBytes.data(), magicBytes.size()); - memcpy(buf.data() + magicBytes.size(), buffer, length); - - return buf; -} - -static constexpr int srcHashOffset = 8; - -static constexpr uint32_t flagsHash = 243571335; -static constexpr int flagsHashOffset = 12; - -void Compiler::FixBytecode(const uint8_t* buffer) -{ - // 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, Helpers::CreateV8SourceHash(1)); - - // Overwrite flags hash with the hash used in client js - // !!! Make sure to update the hash if flags in client js change !!! - Helpers::CopyValueToBuffer(buffer, flagsHashOffset, flagsHash); -} +#include "compiler.h" +#include "helpers.h" + +#include + +using namespace BytecodeCompiler; + +bool Compiler::CompileModule(const std::string& fileName, bool compileDependencies) +{ + // Read the file + if(!package->FileExists(fileName)) + { + logger->LogError("File not found: " + fileName); + return false; + } + size_t size = package->GetFileSize(fileName); + std::string sourceCode; + sourceCode.resize(size); + if(!package->ReadFile(fileName, sourceCode.data(), sourceCode.size())) + { + logger->LogError("Failed to read file: " + fileName); + return false; + } + + v8::TryCatch tryCatch(isolate); + v8::Local ctx = v8::Context::New(isolate); + v8::Context::Scope ctxScope(ctx); + + // Compile the file to a JavaScript module + v8::ScriptOrigin origin( + isolate, v8::String::NewFromUtf8(isolate, fileName.c_str()).ToLocalChecked(), 0, 0, false, -1, v8::Local(), false, false, true, v8::Local()); + v8::ScriptCompiler::Source source(v8::String::NewFromUtf8(isolate, sourceCode.c_str()).ToLocalChecked(), origin); + v8::MaybeLocal maybeModule = v8::ScriptCompiler::CompileModule(isolate, &source); + if(maybeModule.IsEmpty() || tryCatch.HasCaught()) + { + logger->LogError("Failed to compile module: " + fileName); + Helpers::CheckTryCatch(fileName, logger, tryCatch, ctx); + return false; + } + + // Retrieve the bytecode from the module + v8::Local module = maybeModule.ToLocalChecked(); + v8::ScriptCompiler::CachedData* cache = v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()); + if(cache == nullptr || tryCatch.HasCaught()) + { + logger->LogError("Failed to create bytecode: " + fileName); + Helpers::CheckTryCatch(fileName, logger, tryCatch, ctx); + return false; + } + + // Write the bytecode to file + std::vector bytecodeResult = CreateBytecodeBuffer(cache->data, cache->length, sourceCode.size()); + bool writeResult = package->WriteFile(fileName, (void*)bytecodeResult.data(), bytecodeResult.size()); + if(!writeResult) + { + logger->LogError("Failed to write to file: " + fileName); + return false; + } + + // Make sure the byte buffer is deleted with the cached data from V8 + cache->buffer_policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferOwned; + delete cache; + + logger->Log("Converted file to bytecode: " + logger->GetHighlightColor() + fileName); + compiledFiles.push_back(fileName); + + // Compile all dependencies + if(compileDependencies) + { + v8::Local ctx = v8::Context::New(isolate); + v8::Local dependencies = module->GetModuleRequests(); + int length = dependencies->Length(); + for(int i = 0; i < length; i++) + { + v8::Local dep = dependencies->Get(ctx, i); + v8::Local request = dep.As(); + // Ignore all imports with import assertions, as those are not loaded as + // normal JS files + if(request->GetImportAssertions()->Length() > 0) continue; + + v8::Local depStr = request->GetSpecifier(); + std::string depPath = *v8::String::Utf8Value(isolate, depStr); + // Ignore the built-in modules + if(std::find(ignoredModules.begin(), ignoredModules.end(), depPath) != ignoredModules.end()) continue; + + // Compile the dependency file + std::string fullFileName = package->ResolveFile(depPath, fileName); + if(!package->FileExists(fullFileName)) + { + logger->LogError("File not found: " + depPath); + return false; + } + + // 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; + } + } + + return true; +} + +bool Compiler::IsBytecodeFile(void* buffer, size_t size) +{ + if(size < magicBytes.size()) return false; + if(memcmp(buffer, magicBytes.data(), magicBytes.size()) != 0) return false; + return true; +} + +std::vector Compiler::CreateBytecodeBuffer(const uint8_t* buffer, int length, int sourceLength) +{ + // Make necessary changes to the bytecode + 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() + sizeof(int) + length; + buf.resize(bufSize); + + memcpy(buf.data(), magicBytes.data(), magicBytes.size()); + memcpy(buf.data() + magicBytes.size(), &sourceLength, sizeof(int)); + memcpy(buf.data() + magicBytes.size() + sizeof(int), buffer, length); + + return buf; +} + +static constexpr int srcHashOffset = 8; + +static constexpr uint32_t flagsHash = 243571335; +static constexpr int flagsHashOffset = 12; + +void Compiler::FixBytecode(const uint8_t* buffer, int sourceLength) +{ + // 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, Helpers::CreateV8SourceHash(sourceLength + 2)); + + // Overwrite flags hash with the hash used in client js + // !!! Make sure to update the hash if flags in client js change !!! + Helpers::CopyValueToBuffer(buffer, flagsHashOffset, flagsHash); +} 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