Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: multi-isolate support for NodePlatform #16700

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 7 additions & 35 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,9 @@

namespace node {

inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
uint32_t* zero_fill_field) :

// Create string and private symbol properties as internalized one byte strings.
//
// Internalized because it makes property lookups a little faster and because
// the string is created in the old space straight away. It's going to end up
// in the old space sooner or later anyway but now it doesn't go through
// v8::Eternal's new space handling first.
//
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
// decoding step. It's a one-time cost, but why pay it when you don't have to?
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
v8::Private::New( \
isolate, \
v8::String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked())),
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
#undef V
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
v8::String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked()),
PER_ISOLATE_STRING_PROPERTIES(V)
#undef V
event_loop_(event_loop), zero_fill_field_(zero_fill_field) {}
inline v8::Isolate* IsolateData::isolate() const {
return isolate_;
}

inline uv_loop_t* IsolateData::event_loop() const {
return event_loop_;
Expand All @@ -81,6 +49,10 @@ inline uint32_t* IsolateData::zero_fill_field() const {
return zero_fill_field_;
}

inline MultiIsolatePlatform* IsolateData::platform() const {
return platform_;
}

inline Environment::AsyncHooks::AsyncHooks(v8::Isolate* isolate)
: isolate_(isolate),
fields_(isolate, kFieldsCount),
Expand Down
53 changes: 53 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "async-wrap.h"
#include "v8-profiler.h"
#include "node_buffer.h"
#include "node_platform.h"

#if defined(_MSC_VER)
#define getpid GetCurrentProcessId
Expand All @@ -17,10 +18,62 @@ namespace node {
using v8::Context;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Message;
using v8::Private;
using v8::StackFrame;
using v8::StackTrace;
using v8::String;

IsolateData::IsolateData(Isolate* isolate,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
uint32_t* zero_fill_field) :

// Create string and private symbol properties as internalized one byte strings.
//
// Internalized because it makes property lookups a little faster and because
// the string is created in the old space straight away. It's going to end up
// in the old space sooner or later anyway but now it doesn't go through
// v8::Eternal's new space handling first.
//
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
// decoding step. It's a one-time cost, but why pay it when you don't have to?
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
Private::New( \
isolate, \
String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked())),
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
#undef V
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked()),
PER_ISOLATE_STRING_PROPERTIES(V)
#undef V
isolate_(isolate),
event_loop_(event_loop),
zero_fill_field_(zero_fill_field),
platform_(platform) {
if (platform_ != nullptr)
platform_->RegisterIsolate(this, event_loop);
}

IsolateData::~IsolateData() {
if (platform_ != nullptr)
platform_->UnregisterIsolate(this);
}

void Environment::Start(int argc,
const char* const* argv,
Expand Down
10 changes: 8 additions & 2 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,13 @@ struct node_async_ids {

class IsolateData {
public:
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
uint32_t* zero_fill_field = nullptr);
IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
MultiIsolatePlatform* platform = nullptr,
uint32_t* zero_fill_field = nullptr);
~IsolateData();
inline uv_loop_t* event_loop() const;
inline uint32_t* zero_fill_field() const;
inline MultiIsolatePlatform* platform() const;

#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
Expand All @@ -357,6 +360,7 @@ class IsolateData {
#undef VP

std::unordered_map<nghttp2_rcbuf*, v8::Eternal<v8::String>> http2_static_strs;
inline v8::Isolate* isolate() const;

private:
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
Expand All @@ -369,8 +373,10 @@ class IsolateData {
#undef VS
#undef VP

v8::Isolate* const isolate_;
uv_loop_t* const event_loop_;
uint32_t* const zero_fill_field_;
MultiIsolatePlatform* platform_;

DISALLOW_COPY_AND_ASSIGN(IsolateData);
};
Expand Down
2 changes: 1 addition & 1 deletion src/inspector_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ class NodeInspectorClient : public V8InspectorClient {
terminated_ = false;
running_nested_loop_ = true;
while (!terminated_ && channel_->waitForFrontendMessage()) {
platform_->FlushForegroundTasksInternal();
platform_->FlushForegroundTasks(env_->isolate());
}
terminated_ = false;
running_nested_loop_ = false;
Expand Down
47 changes: 36 additions & 11 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,10 @@ node::DebugOptions debug_options;

static struct {
#if NODE_USE_V8_PLATFORM
void Initialize(int thread_pool_size, uv_loop_t* loop) {
void Initialize(int thread_pool_size) {
tracing_agent_ =
trace_enabled ? new tracing::Agent() : nullptr;
platform_ = new NodePlatform(thread_pool_size, loop,
platform_ = new NodePlatform(thread_pool_size,
trace_enabled ? tracing_agent_->GetTracingController() : nullptr);
V8::InitializePlatform(platform_);
tracing::TraceEventHelper::SetTracingController(
Expand All @@ -280,8 +280,12 @@ static struct {
tracing_agent_ = nullptr;
}

void DrainVMTasks() {
platform_->DrainBackgroundTasks();
void DrainVMTasks(Isolate* isolate) {
platform_->DrainBackgroundTasks(isolate);
}

void CancelVMTasks(Isolate* isolate) {
platform_->CancelPendingDelayedTasks(isolate);
}

#if HAVE_INSPECTOR
Expand All @@ -306,12 +310,17 @@ static struct {
tracing_agent_->Stop();
}

NodePlatform* Platform() {
return platform_;
}

tracing::Agent* tracing_agent_;
NodePlatform* platform_;
#else // !NODE_USE_V8_PLATFORM
void Initialize(int thread_pool_size, uv_loop_t* loop) {}
void Initialize(int thread_pool_size) {}
void Dispose() {}
void DrainVMTasks() {}
void DrainVMTasks(Isolate* isolate) {}
void CancelVMTasks(Isolate* isolate) {}
bool StartInspector(Environment *env, const char* script_path,
const node::DebugOptions& options) {
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
Expand All @@ -323,6 +332,10 @@ static struct {
"so event tracing is not available.\n");
}
void StopTracingAgent() {}

NodePlatform* Platform() {
return nullptr;
}
#endif // !NODE_USE_V8_PLATFORM

#if !NODE_USE_V8_PLATFORM || !HAVE_INSPECTOR
Expand Down Expand Up @@ -4431,7 +4444,14 @@ int EmitExit(Environment* env) {


IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) {
return new IsolateData(isolate, loop);
return new IsolateData(isolate, loop, nullptr);
}

IsolateData* CreateIsolateData(
Isolate* isolate,
uv_loop_t* loop,
MultiIsolatePlatform* platform) {
return new IsolateData(isolate, loop, platform);
}


Expand Down Expand Up @@ -4516,7 +4536,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
do {
uv_run(env.event_loop(), UV_RUN_DEFAULT);

v8_platform.DrainVMTasks();
v8_platform.DrainVMTasks(isolate);

more = uv_loop_alive(env.event_loop());
if (more)
Expand All @@ -4537,7 +4557,8 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
RunAtExit(&env);
uv_key_delete(&thread_local_env);

v8_platform.DrainVMTasks();
v8_platform.DrainVMTasks(isolate);
v8_platform.CancelVMTasks(isolate);
WaitForInspectorDisconnect(&env);
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
Expand Down Expand Up @@ -4580,7 +4601,11 @@ inline int Start(uv_loop_t* event_loop,
Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
IsolateData isolate_data(isolate, event_loop, allocator.zero_fill_field());
IsolateData isolate_data(
isolate,
event_loop,
v8_platform.Platform(),
allocator.zero_fill_field());
exit_code = Start(isolate, &isolate_data, argc, argv, exec_argc, exec_argv);
}

Expand Down Expand Up @@ -4627,7 +4652,7 @@ int Start(int argc, char** argv) {
V8::SetEntropySource(crypto::EntropySource);
#endif // HAVE_OPENSSL

v8_platform.Initialize(v8_thread_pool_size, uv_default_loop());
v8_platform.Initialize(v8_thread_pool_size);
// Enable tracing when argv has --trace-events-enabled.
if (trace_enabled) {
fprintf(stderr, "Warning: Trace event is an experimental feature "
Expand Down
25 changes: 23 additions & 2 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#endif

#include "v8.h" // NOLINT(build/include_order)
#include "v8-platform.h" // NOLINT(build/include_order)
#include "node_version.h" // NODE_MODULE_VERSION

#define NODE_MAKE_VERSION(major, minor, patch) \
Expand Down Expand Up @@ -209,8 +210,28 @@ NODE_EXTERN void Init(int* argc,
class IsolateData;
class Environment;

NODE_EXTERN IsolateData* CreateIsolateData(v8::Isolate* isolate,
struct uv_loop_s* loop);
class MultiIsolatePlatform : public v8::Platform {
public:
virtual ~MultiIsolatePlatform() { }
virtual void DrainBackgroundTasks(v8::Isolate* isolate) = 0;
virtual void CancelPendingDelayedTasks(v8::Isolate* isolate) = 0;

// These will be called by the `IsolateData` creation/destruction functions.
virtual void RegisterIsolate(IsolateData* isolate_data,
struct uv_loop_s* loop) = 0;
virtual void UnregisterIsolate(IsolateData* isolate_data) = 0;
};

// If `platform` is passed, it will be used to register new Worker instances.
// It can be `nullptr`, in which case creating new Workers inside of
// Environments that use this `IsolateData` will not work.
NODE_EXTERN IsolateData* CreateIsolateData(
v8::Isolate* isolate,
struct uv_loop_s* loop);
NODE_EXTERN IsolateData* CreateIsolateData(
v8::Isolate* isolate,
struct uv_loop_s* loop,
MultiIsolatePlatform* platform);
NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);

NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
Expand Down
Loading