diff options
author | Joyee Cheung <joyeec9h3@gmail.com> | 2021-11-18 06:56:39 +0300 |
---|---|---|
committer | Bryan English <bryan@bryanenglish.com> | 2022-05-30 19:26:49 +0300 |
commit | 85d81a764f7ddd60a18ea772bf912950b0818b2f (patch) | |
tree | 786c07ce8692d404f57e5057006a96a091fb91a4 /tools | |
parent | 82fb037388f510fde52558c8e19746a5ebb63938 (diff) |
bootstrap: include code cache in the embedded snapshot
Since V8 code cache encodes indices to the read-only space
it is safer to make sure that the code cache is generated in the
same heap used to generate the embdded snapshot. This patch
merges the code cache builder into the snapshot builder and
makes the code cache part of node::SnapshotData that is
deserialized into the native module loader during bootstrap.
PR-URL: https://github.com/nodejs/node/pull/43023
Fixes: https://github.com/nodejs/node/issues/31074
Refs: https://github.com/nodejs/node/issues/35711
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/code_cache/README.md | 38 | ||||
-rw-r--r-- | tools/code_cache/cache_builder.cc | 148 | ||||
-rw-r--r-- | tools/code_cache/cache_builder.h | 16 | ||||
-rw-r--r-- | tools/code_cache/mkcodecache.cc | 74 |
4 files changed, 0 insertions, 276 deletions
diff --git a/tools/code_cache/README.md b/tools/code_cache/README.md deleted file mode 100644 index 8feb280caae..00000000000 --- a/tools/code_cache/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Node.js code cache builder - -This is the V8 code cache builder of Node.js. It pre-compiles all the -JavaScript native modules of Node.js and serializes the code cache (including -the bytecodes) that will be embedded into the Node.js executable. When a Node.js -JavaScript native module is `require`d at runtime, Node.js can deserialize from -the code cache instead of parsing the source code and generating the bytecode -for it before execution, which should reduce the load time of these JavaScript -native modules. - -## How it's built and used - -The code cache builder is built with the `mkcodecache` target in `node.gyp` -when `node_use_node_code_cache` is set to true, which is currently done by -default. - -In the default build of the Node.js executable, to embed the V8 code cache of -the native modules into the Node.js executable, `libnode` is first built with -these unresolved symbols: - -- `node::native_module::has_code_cache` -- `node::native_module::NativeModuleEnv::InitializeCodeCache` - -Then the `mkcodecache` executable is built with C++ files in this directory, -as well as `src/node_code_cache_stub.cc` which defines the unresolved symbols. - -`mkcodecache` is run to generate a C++ file -`<(SHARED_INTERMEDIATE_DIR)/node_code_cache.cc` that is similar to -`src/node_code_cache_stub.cc` in structure, but contains the code cache data -written as static char array literals. Then `libnode` is built with -`node_code_cache.cc` to produce the final Node.js executable with the code -cache data embedded. - -For debugging, Node.js can be built without code cache if -`--without-node-code-cache` is passed to `configure`. Note that even if the -code cache is not pre-compiled and embedded into the Node.js executable, the -internal infrastructure is still used to share code cache between the main -thread and worker threads (if there is any). diff --git a/tools/code_cache/cache_builder.cc b/tools/code_cache/cache_builder.cc deleted file mode 100644 index 837357a0fbd..00000000000 --- a/tools/code_cache/cache_builder.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "cache_builder.h" -#include "debug_utils-inl.h" -#include "node_native_module.h" -#include "util.h" - -#include <iostream> -#include <map> -#include <sstream> -#include <vector> -#include <cstdlib> - -namespace node { -namespace native_module { - -using v8::Context; -using v8::Local; -using v8::ScriptCompiler; - -static std::string GetDefName(const std::string& id) { - char buf[64] = {0}; - size_t size = id.size(); - CHECK_LT(size, sizeof(buf)); - for (size_t i = 0; i < size; ++i) { - char ch = id[i]; - buf[i] = (ch == '-' || ch == '/') ? '_' : ch; - } - return buf; -} - -static std::string FormatSize(size_t size) { - char buf[64] = {0}; - if (size < 1024) { - snprintf(buf, sizeof(buf), "%.2fB", static_cast<double>(size)); - } else if (size < 1024 * 1024) { - snprintf(buf, sizeof(buf), "%.2fKB", static_cast<double>(size / 1024)); - } else { - snprintf( - buf, sizeof(buf), "%.2fMB", static_cast<double>(size / 1024 / 1024)); - } - return buf; -} - -static std::string GetDefinition(const std::string& id, - size_t size, - const uint8_t* data) { - std::stringstream ss; - ss << "static const uint8_t " << GetDefName(id) << "[] = {\n"; - for (size_t i = 0; i < size; ++i) { - uint8_t ch = data[i]; - ss << std::to_string(ch) << (i == size - 1 ? '\n' : ','); - } - ss << "};"; - return ss.str(); -} - -static void GetInitializer(const std::string& id, std::stringstream& ss) { - std::string def_name = GetDefName(id); - ss << " code_cache.emplace(\n"; - ss << " \"" << id << "\",\n"; - ss << " std::make_unique<v8::ScriptCompiler::CachedData>(\n"; - ss << " " << def_name << ",\n"; - ss << " static_cast<int>(arraysize(" << def_name << ")), policy\n"; - ss << " )\n"; - ss << " );"; -} - -static std::string GenerateCodeCache( - const std::map<std::string, ScriptCompiler::CachedData*>& data) { - std::stringstream ss; - ss << R"(#include <cinttypes> -#include "node_native_module_env.h" - -// This file is generated by mkcodecache (tools/code_cache/mkcodecache.cc) - -namespace node { -namespace native_module { - -const bool has_code_cache = true; - -)"; - - size_t total = 0; - for (const auto& x : data) { - const std::string& id = x.first; - ScriptCompiler::CachedData* cached_data = x.second; - total += cached_data->length; - std::string def = GetDefinition(id, cached_data->length, cached_data->data); - ss << def << "\n\n"; - std::string size_str = FormatSize(cached_data->length); - std::string total_str = FormatSize(total); - per_process::Debug(DebugCategory::CODE_CACHE, - "Generated cache for %s, size = %s, total = %s\n", - id.c_str(), - size_str.c_str(), - total_str.c_str()); - } - - ss << R"(void NativeModuleEnv::InitializeCodeCache() { - NativeModuleCacheMap& code_cache = - *NativeModuleLoader::GetInstance()->code_cache(); - CHECK(code_cache.empty()); - auto policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferNotOwned; -)"; - - for (const auto& x : data) { - GetInitializer(x.first, ss); - ss << "\n\n"; - } - - ss << R"( -} - -} // namespace native_module -} // namespace node -)"; - return ss.str(); -} - -std::string CodeCacheBuilder::Generate(Local<Context> context) { - NativeModuleLoader* loader = NativeModuleLoader::GetInstance(); - std::vector<std::string> ids = loader->GetModuleIds(); - - std::map<std::string, ScriptCompiler::CachedData*> data; - - for (const auto& id : ids) { - // TODO(joyeecheung): we can only compile the modules that can be - // required here because the parameters for other types of builtins - // are still very flexible. We should look into auto-generating - // the parameters from the source somehow. - if (loader->CanBeRequired(id.c_str())) { - NativeModuleLoader::Result result; - USE(loader->CompileAsModule(context, id.c_str(), &result)); - ScriptCompiler::CachedData* cached_data = - loader->GetCodeCache(id.c_str()); - if (cached_data == nullptr) { - // TODO(joyeecheung): display syntax errors - std::cerr << "Failed to compile " << id << "\n"; - } else { - data.emplace(id, cached_data); - } - } - } - - return GenerateCodeCache(data); -} - -} // namespace native_module -} // namespace node diff --git a/tools/code_cache/cache_builder.h b/tools/code_cache/cache_builder.h deleted file mode 100644 index d5a6cd4241d..00000000000 --- a/tools/code_cache/cache_builder.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TOOLS_CODE_CACHE_CACHE_BUILDER_H_ -#define TOOLS_CODE_CACHE_CACHE_BUILDER_H_ - -#include <string> -#include "v8.h" - -namespace node { -namespace native_module { -class CodeCacheBuilder { - public: - static std::string Generate(v8::Local<v8::Context> context); -}; -} // namespace native_module -} // namespace node - -#endif // TOOLS_CODE_CACHE_CACHE_BUILDER_H_ diff --git a/tools/code_cache/mkcodecache.cc b/tools/code_cache/mkcodecache.cc deleted file mode 100644 index 68690252a14..00000000000 --- a/tools/code_cache/mkcodecache.cc +++ /dev/null @@ -1,74 +0,0 @@ -#include <cstdio> -#include <fstream> -#include <iostream> -#include <sstream> -#include <string> - -#include "cache_builder.h" -#include "debug_utils-inl.h" -#include "libplatform/libplatform.h" -#include "v8.h" - -using node::native_module::CodeCacheBuilder; -using v8::ArrayBuffer; -using v8::Context; -using v8::HandleScope; -using v8::Isolate; -using v8::Local; - -#ifdef _WIN32 -#include <VersionHelpers.h> -#include <WinError.h> -#include <windows.h> - -int wmain(int argc, wchar_t* argv[]) { -#else // UNIX -int main(int argc, char* argv[]) { - argv = uv_setup_args(argc, argv); -#endif // _WIN32 - - v8::V8::SetFlagsFromString("--random_seed=42"); - v8::V8::SetFlagsFromString("--harmony-import-assertions"); - - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " <path/to/output.cc>\n"; - return 1; - } - - std::ofstream out; - out.open(argv[1], std::ios::out | std::ios::binary); - if (!out.is_open()) { - std::cerr << "Cannot open " << argv[1] << "\n"; - return 1; - } - - node::per_process::enabled_debug_list.Parse(nullptr); - - std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform(); - v8::V8::InitializePlatform(platform.get()); - v8::V8::Initialize(); - - // Create a new Isolate and make it the current one. - Isolate::CreateParams create_params; - create_params.array_buffer_allocator_shared.reset( - ArrayBuffer::Allocator::NewDefaultAllocator()); - Isolate* isolate = Isolate::New(create_params); - { - Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = v8::Context::New(isolate); - v8::Context::Scope context_scope(context); - - // The command line flags are part of the code cache's checksum so reset - // --random_seed= to its default value before creating the code cache. - v8::V8::SetFlagsFromString("--random_seed=0"); - std::string cache = CodeCacheBuilder::Generate(context); - out << cache; - out.close(); - } - isolate->Dispose(); - - v8::V8::Dispose(); - v8::V8::DisposePlatform(); - return 0; -} |