diff options
Diffstat (limited to 'tools/code_cache/cache_builder.cc')
-rw-r--r-- | tools/code_cache/cache_builder.cc | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/tools/code_cache/cache_builder.cc b/tools/code_cache/cache_builder.cc new file mode 100644 index 00000000000..9ce4efa3a1e --- /dev/null +++ b/tools/code_cache/cache_builder.cc @@ -0,0 +1,165 @@ +#include "cache_builder.h" +#include <iostream> +#include <map> +#include <sstream> +#include <vector> +#include <cstdlib> +#include "util.h" + +#include "node_native_module.h" + +namespace node { +namespace native_module { + +using v8::Context; +using v8::Function; +using v8::Isolate; +using v8::Local; +using v8::MaybeLocal; +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 std::string GetInitializer(const std::string& id) { + std::string def_name = GetDefName(id); + char buf[256] = {0}; + snprintf(buf, + sizeof(buf), + "code_cache->emplace(\n" + " \"%s\",\n" + " std::make_unique<v8::ScriptCompiler::CachedData>" + "(%s, static_cast<int>(arraysize(%s)), policy)\n" + ");", + id.c_str(), + def_name.c_str(), + def_name.c_str()); + return buf; +} + +static std::string GenerateCodeCache( + std::map<std::string, ScriptCompiler::CachedData*> data, + std::vector<std::string> ids, + bool log_progress) { + std::stringstream ss; + ss << R"(#include <cinttypes> +#include "node_native_module_env.h" + +// This file is generated by tools/mkcodecache +// and is used when configure is run with \`--code-cache-path\` + +namespace node { +namespace native_module { +)"; + + 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"; + if (log_progress) { + std::cout << "Generated cache for " << id + << ", size = " << FormatSize(cached_data->length) + << ", total = " << FormatSize(total) << "\n"; + } + } + + ss << R"(void NativeModuleEnv::InitializeCodeCache() { + NativeModuleCacheMap* code_cache = + NativeModuleLoader::GetInstance()->code_cache(); + if (!code_cache->empty()) { + return; + } + auto policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferNotOwned; +)"; + + for (const auto& x : data) { + const std::string& id = x.first; + ss << GetInitializer(id) << "\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::vector<std::string> modules; + modules.reserve(ids.size()); + + std::map<std::string, ScriptCompiler::CachedData*> data; + + NativeModuleLoader::Result result; + 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 paramters from the source somehow. + if (loader->CanBeRequired(id.c_str())) { + modules.push_back(id); + 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 complile " << id << "\n"; + } else { + data.emplace(id, cached_data); + } + } + } + + char env_buf[32]; + size_t env_size = sizeof(env_buf); + int ret = uv_os_getenv("NODE_DEBUG", env_buf, &env_size); + bool log_progress = false; + if (ret == 0 && strcmp(env_buf, "mkcodecache") == 0) { + log_progress = true; + } + return GenerateCodeCache(data, modules, log_progress); +} + +} // namespace native_module +} // namespace node |