mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
tools: implement node_mksnapshot
Implements a node_mksnapshot target that generates a snapshot blob from a Node.js main instance's isolate, and serializes the data blob with other additional data into a C++ file that can be embedded into the Node.js binary. PR-URL: https://github.com/nodejs/node/pull/27321 Refs: https://github.com/nodejs/node/issues/17058 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
parent
ffcc949f1c
commit
d701667950
2
Makefile
2
Makefile
@ -1226,6 +1226,8 @@ LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \
|
||||
tools/icu/*.h \
|
||||
tools/code_cache/*.cc \
|
||||
tools/code_cache/*.h \
|
||||
tools/snapshot/*.cc \
|
||||
tools/snapshot/*.h \
|
||||
))
|
||||
|
||||
# Code blocks don't have newline at the end,
|
||||
|
42
node.gyp
42
node.gyp
@ -1156,7 +1156,47 @@
|
||||
}],
|
||||
],
|
||||
}, # mkcodecache
|
||||
], # end targets
|
||||
{
|
||||
'target_name': 'node_mksnapshot',
|
||||
'type': 'executable',
|
||||
|
||||
'dependencies': [
|
||||
'<(node_lib_target_name)',
|
||||
'deps/histogram/histogram.gyp:histogram',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'node.gypi'
|
||||
],
|
||||
|
||||
'include_dirs': [
|
||||
'src',
|
||||
'tools/msvs/genfiles',
|
||||
'deps/v8/include',
|
||||
'deps/cares/include',
|
||||
'deps/uv/include',
|
||||
],
|
||||
|
||||
'defines': [ 'NODE_WANT_INTERNALS=1' ],
|
||||
|
||||
'sources': [
|
||||
'src/node_code_cache_stub.cc',
|
||||
'tools/snapshot/node_mksnapshot.cc',
|
||||
'tools/snapshot/snapshot_builder.cc',
|
||||
'tools/snapshot/snapshot_builder.h',
|
||||
],
|
||||
|
||||
'conditions': [
|
||||
[ 'node_report=="true"', {
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'libraries': [ 'Ws2_32' ],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, # node_mksnapshot
|
||||
], # end targets
|
||||
|
||||
'conditions': [
|
||||
['OS=="aix" and node_shared=="true"', {
|
||||
|
51
tools/snapshot/node_mksnapshot.cc
Normal file
51
tools/snapshot/node_mksnapshot.cc
Normal file
@ -0,0 +1,51 @@
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "libplatform/libplatform.h"
|
||||
#include "node_internals.h"
|
||||
#include "snapshot_builder.h"
|
||||
#include "v8.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
#else // UNIX
|
||||
int main(int argc, char* argv[]) {
|
||||
#endif // _WIN32
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int node_argc = 1;
|
||||
char argv0[] = "node";
|
||||
char* node_argv[] = {argv0, nullptr};
|
||||
|
||||
node::InitializationResult result =
|
||||
node::InitializeOncePerProcess(node_argc, node_argv);
|
||||
CHECK(!result.early_return);
|
||||
CHECK_EQ(result.exit_code, 0);
|
||||
|
||||
{
|
||||
std::string snapshot =
|
||||
node::SnapshotBuilder::Generate(result.args, result.exec_args);
|
||||
out << snapshot;
|
||||
out.close();
|
||||
}
|
||||
|
||||
node::TearDownOncePerProcess();
|
||||
return 0;
|
||||
}
|
122
tools/snapshot/snapshot_builder.cc
Normal file
122
tools/snapshot/snapshot_builder.cc
Normal file
@ -0,0 +1,122 @@
|
||||
#include "snapshot_builder.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "env-inl.h"
|
||||
#include "node_internals.h"
|
||||
#include "node_main_instance.h"
|
||||
#include "node_v8_platform-inl.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::Context;
|
||||
using v8::HandleScope;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::Locker;
|
||||
using v8::SnapshotCreator;
|
||||
using v8::StartupData;
|
||||
|
||||
std::string FormatBlob(v8::StartupData* blob,
|
||||
const std::vector<size_t>& isolate_data_indexes) {
|
||||
std::stringstream ss;
|
||||
size_t isolate_data_indexes_size = isolate_data_indexes.size();
|
||||
|
||||
ss << R"(#include <cstddef>
|
||||
#include "node_main_instance.h"
|
||||
#include "v8.h"
|
||||
|
||||
// This file is generated by tools/snapshot. Do not edit.
|
||||
|
||||
namespace node {
|
||||
|
||||
static const uint8_t blob_data[] = {
|
||||
)";
|
||||
|
||||
for (int i = 0; i < blob->raw_size; i++) {
|
||||
uint8_t ch = blob->data[i];
|
||||
ss << std::to_string(ch) << ((i == blob->raw_size - 1) ? '\n' : ',');
|
||||
}
|
||||
|
||||
ss << R"(};
|
||||
|
||||
static const int blob_size = )"
|
||||
<< blob->raw_size << R"(;
|
||||
static v8::StartupData blob = {
|
||||
reinterpret_cast<const char*>(blob_data),
|
||||
blob_size
|
||||
};
|
||||
)";
|
||||
|
||||
ss << R"(v8::StartupData*
|
||||
NodeMainInstance::GetEmbeddedSnapshotBlob() {
|
||||
return &blob;
|
||||
}
|
||||
|
||||
static const size_t isolate_data_indexes_raw[] = {
|
||||
)";
|
||||
for (size_t i = 0; i < isolate_data_indexes_size; i++) {
|
||||
ss << std::to_string(isolate_data_indexes[i])
|
||||
<< ((i == isolate_data_indexes_size - 1) ? '\n' : ',');
|
||||
}
|
||||
ss << "};\n\n";
|
||||
|
||||
ss << "static const size_t isolate_data_indexes_size = "
|
||||
<< isolate_data_indexes_size << R"(;
|
||||
|
||||
NodeMainInstance::IndexArray isolate_data_indexes {
|
||||
isolate_data_indexes_raw,
|
||||
isolate_data_indexes_size
|
||||
};
|
||||
|
||||
const NodeMainInstance::IndexArray*
|
||||
NodeMainInstance::GetIsolateDataIndexes() {
|
||||
return &isolate_data_indexes;
|
||||
}
|
||||
} // namespace node
|
||||
)";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string SnapshotBuilder::Generate(
|
||||
const std::vector<std::string> args,
|
||||
const std::vector<std::string> exec_args) {
|
||||
// TODO(joyeecheung): collect external references and set it in
|
||||
// params.external_references.
|
||||
std::vector<intptr_t> external_references = {
|
||||
reinterpret_cast<intptr_t>(nullptr)};
|
||||
Isolate* isolate = Isolate::Allocate();
|
||||
per_process::v8_platform.Platform()->RegisterIsolate(isolate,
|
||||
uv_default_loop());
|
||||
NodeMainInstance* main_instance = nullptr;
|
||||
std::string result;
|
||||
|
||||
{
|
||||
std::vector<size_t> isolate_data_indexes;
|
||||
SnapshotCreator creator(isolate, external_references.data());
|
||||
{
|
||||
main_instance =
|
||||
NodeMainInstance::Create(isolate,
|
||||
uv_default_loop(),
|
||||
per_process::v8_platform.Platform(),
|
||||
args,
|
||||
exec_args);
|
||||
HandleScope scope(isolate);
|
||||
creator.SetDefaultContext(Context::New(isolate));
|
||||
isolate_data_indexes = main_instance->isolate_data()->Serialize(&creator);
|
||||
}
|
||||
|
||||
// Must be out of HandleScope
|
||||
StartupData blob =
|
||||
creator.CreateBlob(SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
// Must be done while the snapshot creator isolate is entered i.e. the
|
||||
// creator is still alive.
|
||||
main_instance->Dispose();
|
||||
result = FormatBlob(&blob, isolate_data_indexes);
|
||||
delete blob.data;
|
||||
}
|
||||
|
||||
per_process::v8_platform.Platform()->UnregisterIsolate(isolate);
|
||||
return result;
|
||||
}
|
||||
} // namespace node
|
15
tools/snapshot/snapshot_builder.h
Normal file
15
tools/snapshot/snapshot_builder.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_
|
||||
#define TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace node {
|
||||
class SnapshotBuilder {
|
||||
public:
|
||||
static std::string Generate(const std::vector<std::string> args,
|
||||
const std::vector<std::string> exec_args);
|
||||
};
|
||||
} // namespace node
|
||||
|
||||
#endif // TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_
|
Loading…
Reference in New Issue
Block a user