summaryrefslogtreecommitdiff
path: root/tools/code_cache/cache_builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/code_cache/cache_builder.cc')
-rw-r--r--tools/code_cache/cache_builder.cc165
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 0000000000..9ce4efa3a1
--- /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