-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools: implement mkcodecache as an executable
This patch implement a mkcodecache executable on top of the `NativeModuleLoader` singleton. This makes it possible to build a Node.js binary with embedded code cache without building itself using the code cache stub - the cache is now initialized by `NativeModuleEnv` instead which can be refactored out of the mkcodecache dependencies. PR-URL: #27161 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
- Loading branch information
1 parent
1c26169
commit 4fd7193
Showing
9 changed files
with
322 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#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_ |
Oops, something went wrong.