From 076c31f3eff309df8f7e0129db7a8a1982b3e944 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 19 Apr 2019 12:50:38 +0800 Subject: [PATCH 01/10] src: allow creating NodeMainInstance that does not own the isolate Allows instantiating a NodeMainInstance with an isolate whose initialization and disposal are controlled by the caller. --- src/api/environment.cc | 36 +++++++++++++++------ src/node.cc | 8 +++-- src/node_internals.h | 3 ++ src/node_main_instance.cc | 67 +++++++++++++++++++++++++++++++-------- src/node_main_instance.h | 48 ++++++++++++++++++++++++---- 5 files changed, 131 insertions(+), 31 deletions(-) diff --git a/src/api/environment.cc b/src/api/environment.cc index 0543e0323d8ee2..9a29ad1e5e1ff0 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -183,17 +183,33 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) { #endif } +void SetIsolateUpForNode(v8::Isolate* isolate, IsolateSettingCategories cat) { + switch (cat) { + case IsolateSettingCategories::kErrorHandlers: + isolate->AddMessageListenerWithErrorLevel( + OnMessage, + Isolate::MessageErrorLevel::kMessageError | + Isolate::MessageErrorLevel::kMessageWarning); + isolate->SetAbortOnUncaughtExceptionCallback( + ShouldAbortOnUncaughtException); + isolate->SetFatalErrorHandler(OnFatalError); + break; + case IsolateSettingCategories::kMisc: + isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit); + isolate->SetAllowWasmCodeGenerationCallback( + AllowWasmCodeGenerationCallback); + isolate->SetPromiseRejectCallback(task_queue::PromiseRejectCallback); + v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate); + break; + default: + UNREACHABLE(); + break; + } +} + void SetIsolateUpForNode(v8::Isolate* isolate) { - isolate->AddMessageListenerWithErrorLevel( - OnMessage, - Isolate::MessageErrorLevel::kMessageError | - Isolate::MessageErrorLevel::kMessageWarning); - isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException); - isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit); - isolate->SetFatalErrorHandler(OnFatalError); - isolate->SetAllowWasmCodeGenerationCallback(AllowWasmCodeGenerationCallback); - isolate->SetPromiseRejectCallback(task_queue::PromiseRejectCallback); - v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate); + SetIsolateUpForNode(isolate, IsolateSettingCategories::kErrorHandlers); + SetIsolateUpForNode(isolate, IsolateSettingCategories::kMisc); } Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) { diff --git a/src/node.cc b/src/node.cc index 8efc20475df553..749d8921612cf5 100644 --- a/src/node.cc +++ b/src/node.cc @@ -885,8 +885,12 @@ int Start(int argc, char** argv) { } { - NodeMainInstance main_instance( - uv_default_loop(), result.args, result.exec_args); + Isolate::CreateParams params; + NodeMainInstance main_instance(¶ms, + uv_default_loop(), + per_process::v8_platform.Platform(), + result.args, + result.exec_args); result.exit_code = main_instance.Run(); } diff --git a/src/node_internals.h b/src/node_internals.h index 3fc6ea07361a27..fc924e3e1637ce 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -319,6 +319,9 @@ struct InitializationResult { }; InitializationResult InitializeOncePerProcess(int argc, char** argv); void TearDownOncePerProcess(); +enum class IsolateSettingCategories { kErrorHandlers, kMisc }; +void SetIsolateUpForNode(v8::Isolate* isolate, IsolateSettingCategories cat); +void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params); #if HAVE_INSPECTOR namespace profiler { diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 6ef992d006f79c..4b05149b23c163 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -12,30 +12,70 @@ using v8::Local; using v8::Locker; using v8::SealHandleScope; -NodeMainInstance::NodeMainInstance(uv_loop_t* event_loop, +NodeMainInstance::NodeMainInstance(Isolate* isolate, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args) + : args_(args), + exec_args_(exec_args), + array_buffer_allocator_(nullptr), + isolate_(isolate), + platform_(platform), + isolate_data_(nullptr), + owns_isolate_(false) { + isolate_data_.reset(new IsolateData(isolate_, event_loop, platform, nullptr)); + SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc); +} + +NodeMainInstance* NodeMainInstance::Create( + Isolate* isolate, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args) { + return new NodeMainInstance(isolate, event_loop, platform, args, exec_args); +} + +NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, const std::vector& args, const std::vector& exec_args) : args_(args), exec_args_(exec_args), array_buffer_allocator_(ArrayBufferAllocator::Create()), isolate_(nullptr), - isolate_data_(nullptr) { - // TODO(joyeecheung): when we implement snapshot integration this needs to - // set params.external_references. - Isolate::CreateParams params; - params.array_buffer_allocator = array_buffer_allocator_.get(); - isolate_ = - NewIsolate(¶ms, event_loop, per_process::v8_platform.Platform()); + platform_(platform), + isolate_data_(nullptr), + owns_isolate_(true) { + params->array_buffer_allocator = array_buffer_allocator_.get(); + isolate_ = Isolate::Allocate(); CHECK_NOT_NULL(isolate_); - isolate_data_.reset(CreateIsolateData(isolate_, - event_loop, - per_process::v8_platform.Platform(), - array_buffer_allocator_.get())); + // Register the isolate on the platform before the isolate gets initialized, + // so that the isolate can access the platform during initialization. + platform->RegisterIsolate(isolate_, event_loop); + SetIsolateCreateParamsForNode(params); + Isolate::Initialize(isolate_, *params); + + isolate_data_.reset(new IsolateData( + isolate_, event_loop, platform, array_buffer_allocator_.get())); + SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc); + SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); +} + +void NodeMainInstance::Dispose() { + CHECK(!owns_isolate_); + platform_->DrainTasks(isolate_); + delete this; } NodeMainInstance::~NodeMainInstance() { + if (!owns_isolate_) { + return; + } isolate_->Dispose(); - per_process::v8_platform.Platform()->UnregisterIsolate(isolate_); + platform_->UnregisterIsolate(isolate_); } int NodeMainInstance::Run() { @@ -120,6 +160,7 @@ std::unique_ptr NodeMainInstance::CreateMainEnvironment( } Local context = NewContext(isolate_); + CHECK(!context.IsEmpty()); Context::Scope context_scope(context); std::unique_ptr env = std::make_unique( diff --git a/src/node_main_instance.h b/src/node_main_instance.h index f140edcfd72277..5e463ec57f6209 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -3,6 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#include #include "node.h" #include "util.h" #include "uv.h" @@ -14,12 +15,35 @@ namespace node { // We may be able to create an abstract class to reuse some of the routines. class NodeMainInstance { public: - NodeMainInstance(const NodeMainInstance&) = delete; - NodeMainInstance& operator=(const NodeMainInstance&) = delete; - NodeMainInstance(NodeMainInstance&&) = delete; - NodeMainInstance& operator=(NodeMainInstance&&) = delete; + // To create a main instance that does not own the isoalte, + // The caller needs to do: + // + // Isolate* isolate = Isolate::Allocate(); + // platform->RegisterIsolate(isolate, loop); + // isolate->Initialize(...); + // isolate->Enter(); + // NodeMainInstance* main_instance = + // NodeMainInstance::Create(isolate, loop, args, exec_args); + // + // When tearing it down: + // + // main_instance->Cleanup(); // While the isolate is entered + // isolate->Exit(); + // isolate->Dispose(); + // platform->UnregisterIsolate(isolate); + // + // After calling Dispose() the main_instance is no longer accessible. + static NodeMainInstance* Create(v8::Isolate* isolate, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args); + void Dispose(); - NodeMainInstance(uv_loop_t* event_loop, + // Create a main instance that owns the isolate + NodeMainInstance(v8::Isolate::CreateParams* params, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, const std::vector& args, const std::vector& exec_args); ~NodeMainInstance(); @@ -27,16 +51,28 @@ class NodeMainInstance { // Start running the Node.js instances, return the exit code when finished. int Run(); - private: // TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h // and the environment creation routine in workers somehow. std::unique_ptr CreateMainEnvironment(int* exit_code); + private: + NodeMainInstance(const NodeMainInstance&) = delete; + NodeMainInstance& operator=(const NodeMainInstance&) = delete; + NodeMainInstance(NodeMainInstance&&) = delete; + NodeMainInstance& operator=(NodeMainInstance&&) = delete; + + NodeMainInstance(v8::Isolate* isolate, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args); std::vector args_; std::vector exec_args_; std::unique_ptr array_buffer_allocator_; v8::Isolate* isolate_; + MultiIsolatePlatform* platform_; std::unique_ptr isolate_data_; + bool owns_isolate_ = false; }; } // namespace node From e354795ae2275a6438d686cfb52e3e59b0ae359c Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 18 Apr 2019 16:25:32 +0800 Subject: [PATCH 02/10] src: implement IsolateData serialization and deserialization This patch allows serializing per-isolate data into an isolate snapshot and deserializing them from an isolate snapthot. --- src/env.cc | 147 +++++++++++++++++++++++++++----------- src/env.h | 8 ++- src/node_main_instance.cc | 25 +++++-- src/node_main_instance.h | 19 ++++- 4 files changed, 149 insertions(+), 50 deletions(-) diff --git a/src/env.cc b/src/env.cc index ccb3c404f91ba2..ad981f54336bb3 100644 --- a/src/env.cc +++ b/src/env.cc @@ -37,6 +37,7 @@ using v8::NewStringType; using v8::Number; using v8::Object; using v8::Private; +using v8::SnapshotCreator; using v8::StackTrace; using v8::String; using v8::Symbol; @@ -49,22 +50,58 @@ int const Environment::kNodeContextTag = 0x6e6f64; void* const Environment::kNodeContextTagPtr = const_cast( static_cast(&Environment::kNodeContextTag)); -IsolateData::IsolateData(Isolate* isolate, - uv_loop_t* event_loop, - MultiIsolatePlatform* platform, - ArrayBufferAllocator* node_allocator) - : isolate_(isolate), - event_loop_(event_loop), - allocator_(isolate->GetArrayBufferAllocator()), - node_allocator_(node_allocator == nullptr ? - nullptr : node_allocator->GetImpl()), - uses_node_allocator_(allocator_ == node_allocator_), - platform_(platform) { - CHECK_NOT_NULL(allocator_); +std::vector IsolateData::Serialize(SnapshotCreator* creator) { + Isolate* isolate = creator->GetIsolate(); + std::vector indexes; + HandleScope handle_scope(isolate); + // XXX(joyeecheung): technically speaking, the indexes here should be + // consecutive and we could just return a range instead of an array, + // but that's not part of the V8 API contract so we use an array + // just to be safe. + +#define VP(PropertyName, StringValue) V(v8::Private, PropertyName) +#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) +#define VS(PropertyName, StringValue) V(v8::String, PropertyName) +#define V(TypeName, PropertyName) \ + indexes.push_back(creator->AddData(PropertyName##_.Get(isolate))); + PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) + PER_ISOLATE_SYMBOL_PROPERTIES(VY) + PER_ISOLATE_STRING_PROPERTIES(VS) +#undef V +#undef VY +#undef VS +#undef VP - options_.reset( - new PerIsolateOptions(*(per_process::cli_options->per_isolate))); + return indexes; +} +void IsolateData::DeserializeProperties( + const NodeMainInstance::IndexArray* indexes) { + size_t i = 0; + HandleScope handle_scope(isolate_); + +#define VP(PropertyName, StringValue) V(v8::Private, PropertyName) +#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) +#define VS(PropertyName, StringValue) V(v8::String, PropertyName) +#define V(TypeName, PropertyName) \ + do { \ + MaybeLocal field = \ + isolate_->GetDataFromSnapshotOnce(indexes->Get(i++)); \ + if (field.IsEmpty()) { \ + fprintf(stderr, "Failed to deserialize " #PropertyName "\n"); \ + } \ + PropertyName##_.Set(isolate_, field.ToLocalChecked()); \ + } while (0); + PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) + PER_ISOLATE_SYMBOL_PROPERTIES(VY) + PER_ISOLATE_STRING_PROPERTIES(VS) +#undef V +#undef VY +#undef VS +#undef VP +} + +void IsolateData::CreateProperties() { // Create string and private symbol properties as internalized one byte // strings after the platform is properly initialized. // @@ -76,44 +113,68 @@ IsolateData::IsolateData(Isolate* isolate, // One byte because our strings are ASCII and we can safely skip V8's UTF-8 // decoding step. - HandleScope handle_scope(isolate); + HandleScope handle_scope(isolate_); -#define V(PropertyName, StringValue) \ - PropertyName ## _.Set( \ - isolate, \ - Private::New( \ - isolate, \ - String::NewFromOneByte( \ - isolate, \ - reinterpret_cast(StringValue), \ - NewStringType::kInternalized, \ - sizeof(StringValue) - 1).ToLocalChecked())); +#define V(PropertyName, StringValue) \ + PropertyName##_.Set( \ + isolate_, \ + Private::New(isolate_, \ + String::NewFromOneByte( \ + isolate_, \ + reinterpret_cast(StringValue), \ + NewStringType::kInternalized, \ + sizeof(StringValue) - 1) \ + .ToLocalChecked())); PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) #undef V -#define V(PropertyName, StringValue) \ - PropertyName ## _.Set( \ - isolate, \ - Symbol::New( \ - isolate, \ - String::NewFromOneByte( \ - isolate, \ - reinterpret_cast(StringValue), \ - NewStringType::kInternalized, \ - sizeof(StringValue) - 1).ToLocalChecked())); +#define V(PropertyName, StringValue) \ + PropertyName##_.Set( \ + isolate_, \ + Symbol::New(isolate_, \ + String::NewFromOneByte( \ + isolate_, \ + reinterpret_cast(StringValue), \ + NewStringType::kInternalized, \ + sizeof(StringValue) - 1) \ + .ToLocalChecked())); PER_ISOLATE_SYMBOL_PROPERTIES(V) #undef V -#define V(PropertyName, StringValue) \ - PropertyName ## _.Set( \ - isolate, \ - String::NewFromOneByte( \ - isolate, \ - reinterpret_cast(StringValue), \ - NewStringType::kInternalized, \ - sizeof(StringValue) - 1).ToLocalChecked()); +#define V(PropertyName, StringValue) \ + PropertyName##_.Set( \ + isolate_, \ + String::NewFromOneByte(isolate_, \ + reinterpret_cast(StringValue), \ + NewStringType::kInternalized, \ + sizeof(StringValue) - 1) \ + .ToLocalChecked()); PER_ISOLATE_STRING_PROPERTIES(V) #undef V } +IsolateData::IsolateData(Isolate* isolate, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + ArrayBufferAllocator* node_allocator, + const NodeMainInstance::IndexArray* indexes) + : isolate_(isolate), + event_loop_(event_loop), + allocator_(isolate->GetArrayBufferAllocator()), + node_allocator_(node_allocator == nullptr ? nullptr + : node_allocator->GetImpl()), + uses_node_allocator_(allocator_ == node_allocator_), + platform_(platform) { + CHECK_NOT_NULL(allocator_); + + options_.reset( + new PerIsolateOptions(*(per_process::cli_options->per_isolate))); + + if (indexes == nullptr) { + CreateProperties(); + } else { + DeserializeProperties(indexes); + } +} + void IsolateData::MemoryInfo(MemoryTracker* tracker) const { #define V(PropertyName, StringValue) \ tracker->TrackField(#PropertyName, PropertyName(isolate())); diff --git a/src/env.h b/src/env.h index cfef54dcbd7b3e..8d910369bc00df 100644 --- a/src/env.h +++ b/src/env.h @@ -33,6 +33,7 @@ #include "node.h" #include "node_binding.h" #include "node_http2_state.h" +#include "node_main_instance.h" #include "node_options.h" #include "req_wrap.h" #include "util.h" @@ -418,10 +419,12 @@ class IsolateData : public MemoryRetainer { IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform = nullptr, - ArrayBufferAllocator* node_allocator = nullptr); + ArrayBufferAllocator* node_allocator = nullptr, + const NodeMainInstance::IndexArray* indexes = nullptr); SET_MEMORY_INFO_NAME(IsolateData); SET_SELF_SIZE(IsolateData); void MemoryInfo(MemoryTracker* tracker) const override; + std::vector Serialize(v8::SnapshotCreator* creator); inline uv_loop_t* event_loop() const; inline MultiIsolatePlatform* platform() const; @@ -451,6 +454,9 @@ class IsolateData : public MemoryRetainer { IsolateData& operator=(const IsolateData&) = delete; private: + void DeserializeProperties(const NodeMainInstance::IndexArray* indexes); + void CreateProperties(); + #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) #define VS(PropertyName, StringValue) V(v8::String, PropertyName) diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 4b05149b23c163..11dfadabb9422d 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -23,7 +23,8 @@ NodeMainInstance::NodeMainInstance(Isolate* isolate, isolate_(isolate), platform_(platform), isolate_data_(nullptr), - owns_isolate_(false) { + owns_isolate_(false), + deserialize_mode_(false) { isolate_data_.reset(new IsolateData(isolate_, event_loop, platform, nullptr)); SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc); } @@ -41,7 +42,8 @@ NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params, uv_loop_t* event_loop, MultiIsolatePlatform* platform, const std::vector& args, - const std::vector& exec_args) + const std::vector& exec_args, + const IndexArray* per_isolate_data_indexes) : args_(args), exec_args_(exec_args), array_buffer_allocator_(ArrayBufferAllocator::Create()), @@ -58,10 +60,20 @@ NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params, SetIsolateCreateParamsForNode(params); Isolate::Initialize(isolate_, *params); - isolate_data_.reset(new IsolateData( - isolate_, event_loop, platform, array_buffer_allocator_.get())); + deserialize_mode_ = per_isolate_data_indexes != nullptr; + // If the indexes are not nullptr, we are not deserializing + CHECK_IMPLIES(deserialize_mode_, params->external_references != nullptr); + isolate_data_.reset(new IsolateData(isolate_, + event_loop, + platform, + array_buffer_allocator_.get(), + per_isolate_data_indexes)); SetIsolateUpForNode(isolate_, IsolateSettingCategories::kMisc); - SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); + if (!deserialize_mode_) { + // If in deserialize mode, delay until after the deserialization is + // complete. + SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); + } } void NodeMainInstance::Dispose() { @@ -160,6 +172,9 @@ std::unique_ptr NodeMainInstance::CreateMainEnvironment( } Local context = NewContext(isolate_); + if (deserialize_mode_) { + SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); + } CHECK(!context.IsEmpty()); Context::Scope context_scope(context); diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 5e463ec57f6209..8962a1deda3277 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -15,6 +15,18 @@ namespace node { // We may be able to create an abstract class to reuse some of the routines. class NodeMainInstance { public: + // An array of indexes that can be used to deserialize data from a V8 + // snapshot. + struct IndexArray { + const size_t* data; + size_t length; + + size_t Get(size_t index) const { + DCHECK_LT(index, length); + return data[index]; + } + }; + // To create a main instance that does not own the isoalte, // The caller needs to do: // @@ -45,12 +57,15 @@ class NodeMainInstance { uv_loop_t* event_loop, MultiIsolatePlatform* platform, const std::vector& args, - const std::vector& exec_args); + const std::vector& exec_args, + const IndexArray* per_isolate_data_indexes = nullptr); ~NodeMainInstance(); // Start running the Node.js instances, return the exit code when finished. int Run(); + IsolateData* isolate_data() { return isolate_data_.get(); } + // TODO(joyeecheung): align this with the CreateEnvironment exposed in node.h // and the environment creation routine in workers somehow. std::unique_ptr CreateMainEnvironment(int* exit_code); @@ -66,6 +81,7 @@ class NodeMainInstance { MultiIsolatePlatform* platform, const std::vector& args, const std::vector& exec_args); + std::vector args_; std::vector exec_args_; std::unique_ptr array_buffer_allocator_; @@ -73,6 +89,7 @@ class NodeMainInstance { MultiIsolatePlatform* platform_; std::unique_ptr isolate_data_; bool owns_isolate_ = false; + bool deserialize_mode_ = false; }; } // namespace node From de02be6b15a1219ae28f75bf44466608afe6d916 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 18 Apr 2019 16:26:48 +0800 Subject: [PATCH 03/10] 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. --- Makefile | 2 + node.gyp | 50 +++++++++++- tools/snapshot/node_mksnapshot.cc | 53 +++++++++++++ tools/snapshot/snapshot_builder.cc | 122 +++++++++++++++++++++++++++++ tools/snapshot/snapshot_builder.h | 15 ++++ 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 tools/snapshot/node_mksnapshot.cc create mode 100644 tools/snapshot/snapshot_builder.cc create mode 100644 tools/snapshot/snapshot_builder.h diff --git a/Makefile b/Makefile index d4e805c1d54428..0fe3d722a6a14d 100644 --- a/Makefile +++ b/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, diff --git a/node.gyp b/node.gyp index 3dfbe2fc7977a3..ed3d2358bd68ab 100644 --- a/node.gyp +++ b/node.gyp @@ -1154,7 +1154,55 @@ }], ], }, # 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', + ], + + 'conditions': [ + [ 'node_report=="true"', { + 'conditions': [ + ['OS=="win"', { + 'libraries': [ + 'dbghelp.lib', + 'PsApi.lib', + 'Ws2_32.lib', + ], + 'dll_files': [ + 'dbghelp.dll', + 'PsApi.dll', + 'Ws2_32.dll', + ], + }], + ], + }], + ], + }, # node_mksnapshot + ], # end targets 'conditions': [ ['OS=="aix" and node_shared=="true"', { diff --git a/tools/snapshot/node_mksnapshot.cc b/tools/snapshot/node_mksnapshot.cc new file mode 100644 index 00000000000000..4c55345e642a71 --- /dev/null +++ b/tools/snapshot/node_mksnapshot.cc @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include "libplatform/libplatform.h" +#include "node_internals.h" +#include "snapshot_builder.h" +#include "v8.h" + +#ifdef _WIN32 +#include +#include +#include + +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] << " \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[5] = "node"; + char* node_argv[] = {argv0}; + + 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; +} diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc new file mode 100644 index 00000000000000..43928eaf471fb4 --- /dev/null +++ b/tools/snapshot/snapshot_builder.cc @@ -0,0 +1,122 @@ +#include "snapshot_builder.h" +#include +#include +#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& isolate_data_indexes) { + std::stringstream ss; + size_t isolate_data_indexes_size = isolate_data_indexes.size(); + + ss << R"(#include +#include +#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(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 args, + const std::vector exec_args) { + // TODO(joyeecheung): collect external references and set it in + // params.external_references. + std::vector external_references = { + reinterpret_cast(nullptr)}; + Isolate* isolate = Isolate::Allocate(); + per_process::v8_platform.Platform()->RegisterIsolate(isolate, + uv_default_loop()); + NodeMainInstance* main_instance = nullptr; + std::string result; + + { + std::vector 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); + } + + per_process::v8_platform.Platform()->UnregisterIsolate(isolate); + return result; +} +} // namespace node diff --git a/tools/snapshot/snapshot_builder.h b/tools/snapshot/snapshot_builder.h new file mode 100644 index 00000000000000..2e587d078b9bcd --- /dev/null +++ b/tools/snapshot/snapshot_builder.h @@ -0,0 +1,15 @@ +#ifndef TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_ +#define TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_ + +#include +#include + +namespace node { +class SnapshotBuilder { + public: + static std::string Generate(const std::vector args, + const std::vector exec_args); +}; +} // namespace node + +#endif // TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_ From 52c5c052ea104a8aa4ea849e6451b1a0fb482979 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 18 Apr 2019 22:09:28 +0800 Subject: [PATCH 04/10] src: enable snapshot with per-isolate data Enable serializing the isolate from an isolate snapshot generated by node_mksnapshot with per-isolate data. --- node.gyp | 29 +++++++++++++++++++++++++++++ src/node.cc | 15 ++++++++++++++- src/node_main_instance.cc | 1 + src/node_main_instance.h | 5 +++++ src/node_snapshot_stub.cc | 13 +++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/node_snapshot_stub.cc diff --git a/node.gyp b/node.gyp index ed3d2358bd68ab..1541cbdd94006e 100644 --- a/node.gyp +++ b/node.gyp @@ -223,6 +223,7 @@ 'deps/acorn/acorn/dist/acorn.js', 'deps/acorn/acorn-walk/dist/walk.js', ], + 'node_mksnapshot_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)node_mksnapshot<(EXECUTABLE_SUFFIX)', 'mkcodecache_exec': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)mkcodecache<(EXECUTABLE_SUFFIX)', 'conditions': [ [ 'node_shared=="true"', { @@ -430,6 +431,31 @@ 'src/node_code_cache_stub.cc' ], }], + ['want_separate_host_toolset==0', { + 'dependencies': [ + 'node_mksnapshot', + ], + 'actions': [ + { + 'action_name': 'node_mksnapshot', + 'process_outputs_as_sources': 1, + 'inputs': [ + '<(node_mksnapshot_exec)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/node_snapshot.cc', + ], + 'action': [ + '<@(_inputs)', + '<@(_outputs)', + ], + }, + ], + }, { + 'sources': [ + 'src/node_snapshot_stub.cc' + ], + }], ], }, # node_core_target_name { @@ -1039,6 +1065,7 @@ 'defines': [ 'NODE_WANT_INTERNALS=1' ], 'sources': [ + 'src/node_snapshot_stub.cc', 'src/node_code_cache_stub.cc', 'test/cctest/node_test_fixture.cc', 'test/cctest/test_aliased_buffer.cc', @@ -1129,6 +1156,7 @@ 'NODE_WANT_INTERNALS=1' ], 'sources': [ + 'src/node_snapshot_stub.cc', 'src/node_code_cache_stub.cc', 'tools/code_cache/mkcodecache.cc', 'tools/code_cache/cache_builder.cc', @@ -1178,6 +1206,7 @@ 'defines': [ 'NODE_WANT_INTERNALS=1' ], 'sources': [ + 'src/node_snapshot_stub.cc', 'src/node_code_cache_stub.cc', 'tools/snapshot/node_mksnapshot.cc', 'tools/snapshot/snapshot_builder.cc', diff --git a/src/node.cc b/src/node.cc index 749d8921612cf5..ba55a9e181756e 100644 --- a/src/node.cc +++ b/src/node.cc @@ -886,11 +886,24 @@ int Start(int argc, char** argv) { { Isolate::CreateParams params; + // TODO(joyeecheung): collect external references and set it in + // params.external_references. + std::vector external_references = { + reinterpret_cast(nullptr)}; + v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob(); + const NodeMainInstance::IndexArray* indexes = + NodeMainInstance::GetIsolateDataIndexes(); + if (blob != nullptr) { + params.external_references = external_references.data(); + params.snapshot_blob = blob; + } + NodeMainInstance main_instance(¶ms, uv_default_loop(), per_process::v8_platform.Platform(), result.args, - result.exec_args); + result.exec_args, + indexes); result.exit_code = main_instance.Run(); } diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 11dfadabb9422d..419fd767720e4b 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -175,6 +175,7 @@ std::unique_ptr NodeMainInstance::CreateMainEnvironment( if (deserialize_mode_) { SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); } + CHECK(!context.IsEmpty()); Context::Scope context_scope(context); diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 8962a1deda3277..128e488a923f44 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -70,6 +70,11 @@ class NodeMainInstance { // and the environment creation routine in workers somehow. std::unique_ptr CreateMainEnvironment(int* exit_code); + // If nullptr is returned, the binary is not built with embedded + // snapshot. + static const IndexArray* GetIsolateDataIndexes(); + static v8::StartupData* GetEmbeddedSnapshotBlob(); + private: NodeMainInstance(const NodeMainInstance&) = delete; NodeMainInstance& operator=(const NodeMainInstance&) = delete; diff --git a/src/node_snapshot_stub.cc b/src/node_snapshot_stub.cc new file mode 100644 index 00000000000000..c0604237d537c1 --- /dev/null +++ b/src/node_snapshot_stub.cc @@ -0,0 +1,13 @@ +#include "node_main_instance.h" + +namespace node { + +v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() { + return nullptr; +} + +const NodeMainInstance::IndexArray* NodeMainInstance::GetIsolateDataIndexes() { + return nullptr; +} + +} // namespace node From 8248be6a8e6606ffc7aeebc2fbec4cbcec98c8f6 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 20 Apr 2019 17:18:34 +0800 Subject: [PATCH 05/10] src: enable context snapshot after running per-context scripts At build time, snapshot the context after running per-context scripts in the main instance, and in the final build, deserialize the context in the main instance. This provides a ~5% in the misc/startup benchmark when the instance is launched within a process that runs test/fixtures/semicolon.js. --- src/node_main_instance.cc | 8 +++++++- src/node_main_instance.h | 2 ++ tools/snapshot/snapshot_builder.cc | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 419fd767720e4b..0ad6883342562e 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -12,6 +12,8 @@ using v8::Local; using v8::Locker; using v8::SealHandleScope; +const size_t NodeMainInstance::kNodeContextIndex = 0; + NodeMainInstance::NodeMainInstance(Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform, @@ -171,9 +173,13 @@ std::unique_ptr NodeMainInstance::CreateMainEnvironment( isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true); } - Local context = NewContext(isolate_); + Local context; if (deserialize_mode_) { + context = + Context::FromSnapshot(isolate_, kNodeContextIndex).ToLocalChecked(); SetIsolateUpForNode(isolate_, IsolateSettingCategories::kErrorHandlers); + } else { + context = NewContext(isolate_); } CHECK(!context.IsEmpty()); diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 128e488a923f44..2c15762c08eacb 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -75,6 +75,8 @@ class NodeMainInstance { static const IndexArray* GetIsolateDataIndexes(); static v8::StartupData* GetEmbeddedSnapshotBlob(); + static const size_t kNodeContextIndex; + private: NodeMainInstance(const NodeMainInstance&) = delete; NodeMainInstance& operator=(const NodeMainInstance&) = delete; diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc index 43928eaf471fb4..29ce106a4fa330 100644 --- a/tools/snapshot/snapshot_builder.cc +++ b/tools/snapshot/snapshot_builder.cc @@ -105,6 +105,9 @@ std::string SnapshotBuilder::Generate( HandleScope scope(isolate); creator.SetDefaultContext(Context::New(isolate)); isolate_data_indexes = main_instance->isolate_data()->Serialize(&creator); + + size_t index = creator.AddContext(NewContext(isolate)); + CHECK_EQ(index, NodeMainInstance::kNodeContextIndex); } // Must be out of HandleScope From 3055cb1f0e8936b8b986274949956f5374d4184e Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 21 Apr 2019 19:45:43 +0800 Subject: [PATCH 06/10] fixup! tools: implement node_mksnapshot --- node.gyp | 12 ++---------- tools/snapshot/snapshot_builder.cc | 1 + 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/node.gyp b/node.gyp index 1541cbdd94006e..02aff9cd97054b 100644 --- a/node.gyp +++ b/node.gyp @@ -1210,22 +1210,14 @@ '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': [ - 'dbghelp.lib', - 'PsApi.lib', - 'Ws2_32.lib', - ], - 'dll_files': [ - 'dbghelp.dll', - 'PsApi.dll', - 'Ws2_32.dll', - ], + 'libraries': [ 'Ws2_32' ], }], ], }], diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc index 29ce106a4fa330..3942ffdaad25a4 100644 --- a/tools/snapshot/snapshot_builder.cc +++ b/tools/snapshot/snapshot_builder.cc @@ -117,6 +117,7 @@ std::string SnapshotBuilder::Generate( // creator is still alive. main_instance->Dispose(); result = FormatBlob(&blob, isolate_data_indexes); + delete blob.data; } per_process::v8_platform.Platform()->UnregisterIsolate(isolate); From 2ac1d81cc208e7baee6e38ddc1f82a43109d43be Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 21 Apr 2019 20:03:21 +0800 Subject: [PATCH 07/10] src: use std::vector instead of IndexArray --- src/env.cc | 7 ++--- src/env.h | 4 +-- src/node.cc | 2 +- src/node_main_instance.cc | 13 +++++---- src/node_main_instance.h | 27 ++++++------------ src/node_snapshot_stub.cc | 2 +- tools/snapshot/snapshot_builder.cc | 45 ++++++++++-------------------- 7 files changed, 37 insertions(+), 63 deletions(-) diff --git a/src/env.cc b/src/env.cc index ad981f54336bb3..dd967bd1f80297 100644 --- a/src/env.cc +++ b/src/env.cc @@ -75,8 +75,7 @@ std::vector IsolateData::Serialize(SnapshotCreator* creator) { return indexes; } -void IsolateData::DeserializeProperties( - const NodeMainInstance::IndexArray* indexes) { +void IsolateData::DeserializeProperties(const std::vector* indexes) { size_t i = 0; HandleScope handle_scope(isolate_); @@ -86,7 +85,7 @@ void IsolateData::DeserializeProperties( #define V(TypeName, PropertyName) \ do { \ MaybeLocal field = \ - isolate_->GetDataFromSnapshotOnce(indexes->Get(i++)); \ + isolate_->GetDataFromSnapshotOnce((*indexes)[i++]); \ if (field.IsEmpty()) { \ fprintf(stderr, "Failed to deserialize " #PropertyName "\n"); \ } \ @@ -155,7 +154,7 @@ IsolateData::IsolateData(Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform, ArrayBufferAllocator* node_allocator, - const NodeMainInstance::IndexArray* indexes) + const std::vector* indexes) : isolate_(isolate), event_loop_(event_loop), allocator_(isolate->GetArrayBufferAllocator()), diff --git a/src/env.h b/src/env.h index 8d910369bc00df..3a88c189ddb5e0 100644 --- a/src/env.h +++ b/src/env.h @@ -420,7 +420,7 @@ class IsolateData : public MemoryRetainer { uv_loop_t* event_loop, MultiIsolatePlatform* platform = nullptr, ArrayBufferAllocator* node_allocator = nullptr, - const NodeMainInstance::IndexArray* indexes = nullptr); + const std::vector* indexes = nullptr); SET_MEMORY_INFO_NAME(IsolateData); SET_SELF_SIZE(IsolateData); void MemoryInfo(MemoryTracker* tracker) const override; @@ -454,7 +454,7 @@ class IsolateData : public MemoryRetainer { IsolateData& operator=(const IsolateData&) = delete; private: - void DeserializeProperties(const NodeMainInstance::IndexArray* indexes); + void DeserializeProperties(const std::vector* indexes); void CreateProperties(); #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) diff --git a/src/node.cc b/src/node.cc index ba55a9e181756e..d65d469c6fcf83 100644 --- a/src/node.cc +++ b/src/node.cc @@ -891,7 +891,7 @@ int Start(int argc, char** argv) { std::vector external_references = { reinterpret_cast(nullptr)}; v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob(); - const NodeMainInstance::IndexArray* indexes = + const std::vector* indexes = NodeMainInstance::GetIsolateDataIndexes(); if (blob != nullptr) { params.external_references = external_references.data(); diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 0ad6883342562e..7a405f44c31b39 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -40,12 +40,13 @@ NodeMainInstance* NodeMainInstance::Create( return new NodeMainInstance(isolate, event_loop, platform, args, exec_args); } -NodeMainInstance::NodeMainInstance(Isolate::CreateParams* params, - uv_loop_t* event_loop, - MultiIsolatePlatform* platform, - const std::vector& args, - const std::vector& exec_args, - const IndexArray* per_isolate_data_indexes) +NodeMainInstance::NodeMainInstance( + Isolate::CreateParams* params, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args, + const std::vector* per_isolate_data_indexes) : args_(args), exec_args_(exec_args), array_buffer_allocator_(ArrayBufferAllocator::Create()), diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 2c15762c08eacb..5b45354288f411 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -15,18 +15,6 @@ namespace node { // We may be able to create an abstract class to reuse some of the routines. class NodeMainInstance { public: - // An array of indexes that can be used to deserialize data from a V8 - // snapshot. - struct IndexArray { - const size_t* data; - size_t length; - - size_t Get(size_t index) const { - DCHECK_LT(index, length); - return data[index]; - } - }; - // To create a main instance that does not own the isoalte, // The caller needs to do: // @@ -53,12 +41,13 @@ class NodeMainInstance { void Dispose(); // Create a main instance that owns the isolate - NodeMainInstance(v8::Isolate::CreateParams* params, - uv_loop_t* event_loop, - MultiIsolatePlatform* platform, - const std::vector& args, - const std::vector& exec_args, - const IndexArray* per_isolate_data_indexes = nullptr); + NodeMainInstance( + v8::Isolate::CreateParams* params, + uv_loop_t* event_loop, + MultiIsolatePlatform* platform, + const std::vector& args, + const std::vector& exec_args, + const std::vector* per_isolate_data_indexes = nullptr); ~NodeMainInstance(); // Start running the Node.js instances, return the exit code when finished. @@ -72,7 +61,7 @@ class NodeMainInstance { // If nullptr is returned, the binary is not built with embedded // snapshot. - static const IndexArray* GetIsolateDataIndexes(); + static const std::vector* GetIsolateDataIndexes(); static v8::StartupData* GetEmbeddedSnapshotBlob(); static const size_t kNodeContextIndex; diff --git a/src/node_snapshot_stub.cc b/src/node_snapshot_stub.cc index c0604237d537c1..91bc37121d61fe 100644 --- a/src/node_snapshot_stub.cc +++ b/src/node_snapshot_stub.cc @@ -6,7 +6,7 @@ v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() { return nullptr; } -const NodeMainInstance::IndexArray* NodeMainInstance::GetIsolateDataIndexes() { +const std::vector* NodeMainInstance::GetIsolateDataIndexes() { return nullptr; } diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc index 3942ffdaad25a4..15204858b98fab 100644 --- a/tools/snapshot/snapshot_builder.cc +++ b/tools/snapshot/snapshot_builder.cc @@ -16,10 +16,16 @@ using v8::Locker; using v8::SnapshotCreator; using v8::StartupData; +template +void WriteVector(std::stringstream* ss, const T* vec, size_t size) { + for (size_t i = 0; i < size; i++) { + *ss << std::to_string(vec[i]) << (i == size - 1 ? '\n' : ','); + } +} + std::string FormatBlob(v8::StartupData* blob, const std::vector& isolate_data_indexes) { std::stringstream ss; - size_t isolate_data_indexes_size = isolate_data_indexes.size(); ss << R"(#include #include @@ -30,47 +36,26 @@ std::string FormatBlob(v8::StartupData* blob, namespace node { -static const uint8_t blob_data[] = { +static const char 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' : ','); - } - + WriteVector(&ss, blob->data, blob->raw_size); ss << R"(}; static const int blob_size = )" << blob->raw_size << R"(; -static v8::StartupData blob = { - reinterpret_cast(blob_data), - blob_size -}; +static v8::StartupData blob = { blob_data, blob_size }; )"; - ss << R"(v8::StartupData* -NodeMainInstance::GetEmbeddedSnapshotBlob() { + ss << R"(v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() { return &blob; } -static const size_t isolate_data_indexes_raw[] = { +static const std::vector isolate_data_indexes { )"; - 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 -}; + WriteVector(&ss, isolate_data_indexes.data(), isolate_data_indexes.size()); + ss << R"(}; -const NodeMainInstance::IndexArray* -NodeMainInstance::GetIsolateDataIndexes() { +const std::vector* NodeMainInstance::GetIsolateDataIndexes() { return &isolate_data_indexes; } } // namespace node From 1e0210be88e106d949949e5d49aca7ce663c2bea Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 22 Apr 2019 18:26:56 +0800 Subject: [PATCH 08/10] fixup! src: enable context snapshot after running per-context scripts --- src/node_main_instance.cc | 2 -- src/node_main_instance.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc index 7a405f44c31b39..977a689a359474 100644 --- a/src/node_main_instance.cc +++ b/src/node_main_instance.cc @@ -12,8 +12,6 @@ using v8::Local; using v8::Locker; using v8::SealHandleScope; -const size_t NodeMainInstance::kNodeContextIndex = 0; - NodeMainInstance::NodeMainInstance(Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform, diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 5b45354288f411..3517a97a555d7a 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -64,7 +64,7 @@ class NodeMainInstance { static const std::vector* GetIsolateDataIndexes(); static v8::StartupData* GetEmbeddedSnapshotBlob(); - static const size_t kNodeContextIndex; + static const size_t kNodeContextIndex = 0; private: NodeMainInstance(const NodeMainInstance&) = delete; From 0324fe30e19db42fe0872d796494730ef4e2071b Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 22 Apr 2019 18:27:20 +0800 Subject: [PATCH 09/10] fixup! src: allow creating NodeMainInstance that does not own the isolate --- src/node_main_instance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 3517a97a555d7a..2719b49e976ff6 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -3,7 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include +#include #include "node.h" #include "util.h" #include "uv.h" From 90b5d8d6a6834a8259575b598ea6d23f534b7796 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 22 Apr 2019 18:27:40 +0800 Subject: [PATCH 10/10] fixup! tools: implement node_mksnapshot --- tools/snapshot/node_mksnapshot.cc | 6 ++---- tools/snapshot/snapshot_builder.cc | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/snapshot/node_mksnapshot.cc b/tools/snapshot/node_mksnapshot.cc index 4c55345e642a71..c273ba20b610e1 100644 --- a/tools/snapshot/node_mksnapshot.cc +++ b/tools/snapshot/node_mksnapshot.cc @@ -11,8 +11,6 @@ #include "v8.h" #ifdef _WIN32 -#include -#include #include int wmain(int argc, wchar_t* argv[]) { @@ -33,8 +31,8 @@ int main(int argc, char* argv[]) { } int node_argc = 1; - char argv0[5] = "node"; - char* node_argv[] = {argv0}; + char argv0[] = "node"; + char* node_argv[] = {argv0, nullptr}; node::InitializationResult result = node::InitializeOncePerProcess(node_argc, node_argv); diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc index 15204858b98fab..1faa5330ae118f 100644 --- a/tools/snapshot/snapshot_builder.cc +++ b/tools/snapshot/snapshot_builder.cc @@ -27,8 +27,7 @@ std::string FormatBlob(v8::StartupData* blob, const std::vector& isolate_data_indexes) { std::stringstream ss; - ss << R"(#include -#include + ss << R"(#include #include "node_main_instance.h" #include "v8.h"