Skip to content

Commit

Permalink
src: allow creating NodeMainInstance that does not own the isolate
Browse files Browse the repository at this point in the history
Allows instantiating a NodeMainInstance with an isolate
whose initialization and disposal are controlled by the caller.

PR-URL: #27321
Refs: #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>
  • Loading branch information
joyeecheung committed Apr 23, 2019
1 parent d66c7e3 commit 70d887e
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 31 deletions.
36 changes: 26 additions & 10 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,12 @@ int Start(int argc, char** argv) {
}

{
NodeMainInstance main_instance(
uv_default_loop(), result.args, result.exec_args);
Isolate::CreateParams params;
NodeMainInstance main_instance(&params,
uv_default_loop(),
per_process::v8_platform.Platform(),
result.args,
result.exec_args);
result.exit_code = main_instance.Run();
}

Expand Down
3 changes: 3 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
67 changes: 54 additions & 13 deletions src/node_main_instance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>& args,
const std::vector<std::string>& 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<std::string>& args,
const std::vector<std::string>& 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<std::string>& args,
const std::vector<std::string>& 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(&params, 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() {
Expand Down Expand Up @@ -120,6 +160,7 @@ std::unique_ptr<Environment> NodeMainInstance::CreateMainEnvironment(
}

Local<Context> context = NewContext(isolate_);
CHECK(!context.IsEmpty());
Context::Scope context_scope(context);

std::unique_ptr<Environment> env = std::make_unique<Environment>(
Expand Down
48 changes: 42 additions & 6 deletions src/node_main_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cstddef>
#include "node.h"
#include "util.h"
#include "uv.h"
Expand All @@ -14,29 +15,64 @@ 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<std::string>& args,
const std::vector<std::string>& 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<std::string>& args,
const std::vector<std::string>& exec_args);
~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<Environment> 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<std::string>& args,
const std::vector<std::string>& exec_args);
std::vector<std::string> args_;
std::vector<std::string> exec_args_;
std::unique_ptr<ArrayBufferAllocator> array_buffer_allocator_;
v8::Isolate* isolate_;
MultiIsolatePlatform* platform_;
std::unique_ptr<IsolateData> isolate_data_;
bool owns_isolate_ = false;
};

} // namespace node
Expand Down

0 comments on commit 70d887e

Please sign in to comment.