Skip to content

Commit

Permalink
src: prepare v8 platform for multi-isolate support
Browse files Browse the repository at this point in the history
This splits the task queue used for asynchronous tasks scheduled
by V8 in per-isolate queues, so that multiple threads can be supported.

Original-PR-URL: ayojs/ayo#89
Original-Reviewed-By: Timothy Gu <[email protected]>
PR-URL: nodejs#16700
Reviewed-By: James M Snell <[email protected]>
  • Loading branch information
addaleax committed May 22, 2018
1 parent 5b8e46d commit 9065001
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 103 deletions.
46 changes: 7 additions & 39 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()
: async_ids_stack_(env()->isolate(), 16 * 2),
fields_(env()->isolate(), kFieldsCount),
Expand All @@ -93,10 +65,6 @@ inline Environment::AsyncHooks::AsyncHooks()
// which is different from a default context.
async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;

// kAsyncIdCounter should start at 1 because that'll be the id the execution
// context during bootstrap (code that runs before entering uv_run()).
async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;

// Create all the provider strings that will be passed to JS. Place them in
// an array so the array index matches the PROVIDER id offset. This way the
// strings can be retrieved quickly.
Expand Down
61 changes: 61 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
#include "node_internals.h"
#include "async_wrap.h"
#include "v8-profiler.h"
#include "node_buffer.h"
#include "req-wrap-inl.h"
#include "node_platform.h"

#if defined(_MSC_VER)
#define getpid GetCurrentProcessId
#else
#include <unistd.h>
#endif

#include <stdio.h>
#include <algorithm>
Expand All @@ -10,10 +19,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 @@ -346,10 +346,13 @@ class Environment;

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 @@ -362,6 +365,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 @@ -374,8 +378,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 @@ -314,7 +314,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
43 changes: 31 additions & 12 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,17 +273,17 @@ 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) {
if (trace_enabled) {
tracing_agent_.reset(new tracing::Agent(trace_file_pattern));
platform_ = new NodePlatform(thread_pool_size, loop,
platform_ = new NodePlatform(thread_pool_size,
tracing_agent_->GetTracingController());
V8::InitializePlatform(platform_);
tracing::TraceEventHelper::SetTracingController(
tracing_agent_->GetTracingController());
} else {
tracing_agent_.reset(nullptr);
platform_ = new NodePlatform(thread_pool_size, loop, nullptr);
platform_ = new NodePlatform(thread_pool_size, nullptr);
V8::InitializePlatform(platform_);
tracing::TraceEventHelper::SetTracingController(
new v8::TracingController());
Expand All @@ -297,8 +297,8 @@ static struct {
tracing_agent_.reset(nullptr);
}

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

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

NodePlatform* Platform() {
return platform_;
}

std::unique_ptr<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) {}
bool StartInspector(Environment *env, const char* script_path,
const node::DebugOptions& options) {
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
Expand All @@ -340,6 +344,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 @@ -4734,7 +4742,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 @@ -4802,7 +4817,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 @@ -4823,7 +4838,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
RunAtExit(&env);
uv_key_delete(&thread_local_env);

v8_platform.DrainVMTasks();
v8_platform.DrainVMTasks(isolate);
WaitForInspectorDisconnect(&env);
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
Expand Down Expand Up @@ -4866,7 +4881,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 @@ -4913,7 +4932,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
24 changes: 22 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 @@ -208,8 +209,27 @@ 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;

// 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

0 comments on commit 9065001

Please sign in to comment.