Skip to content

Commit e65b6ae

Browse files
committed
src: prepare v8 platform for multi-isolate support
This splits the task queue used for asynchronous tasks scheduled by V8 in per-isolate queues, so that multiple threads can be supported. PR-URL: ayojs/ayo#89 Reviewed-By: Timothy Gu <timothygu99@gmail.com>
1 parent 9ad994b commit e65b6ae

10 files changed

Lines changed: 269 additions & 93 deletions

File tree

src/env-inl.h

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,41 +37,9 @@
3737

3838
namespace node {
3939

40-
inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
41-
uint32_t* zero_fill_field) :
42-
43-
// Create string and private symbol properties as internalized one byte strings.
44-
//
45-
// Internalized because it makes property lookups a little faster and because
46-
// the string is created in the old space straight away. It's going to end up
47-
// in the old space sooner or later anyway but now it doesn't go through
48-
// v8::Eternal's new space handling first.
49-
//
50-
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
51-
// decoding step. It's a one-time cost, but why pay it when you don't have to?
52-
#define V(PropertyName, StringValue) \
53-
PropertyName ## _( \
54-
isolate, \
55-
v8::Private::New( \
56-
isolate, \
57-
v8::String::NewFromOneByte( \
58-
isolate, \
59-
reinterpret_cast<const uint8_t*>(StringValue), \
60-
v8::NewStringType::kInternalized, \
61-
sizeof(StringValue) - 1).ToLocalChecked())),
62-
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
63-
#undef V
64-
#define V(PropertyName, StringValue) \
65-
PropertyName ## _( \
66-
isolate, \
67-
v8::String::NewFromOneByte( \
68-
isolate, \
69-
reinterpret_cast<const uint8_t*>(StringValue), \
70-
v8::NewStringType::kInternalized, \
71-
sizeof(StringValue) - 1).ToLocalChecked()),
72-
PER_ISOLATE_STRING_PROPERTIES(V)
73-
#undef V
74-
event_loop_(event_loop), zero_fill_field_(zero_fill_field) {}
40+
inline v8::Isolate* IsolateData::isolate() const {
41+
return isolate_;
42+
}
7543

7644
inline uv_loop_t* IsolateData::event_loop() const {
7745
return event_loop_;
@@ -81,6 +49,10 @@ inline uint32_t* IsolateData::zero_fill_field() const {
8149
return zero_fill_field_;
8250
}
8351

52+
inline MultiIsolatePlatform* IsolateData::platform() const {
53+
return platform_;
54+
}
55+
8456
inline Environment::AsyncHooks::AsyncHooks(v8::Isolate* isolate)
8557
: isolate_(isolate),
8658
fields_(isolate, kFieldsCount),

src/env.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include "async-wrap.h"
33
#include "v8-profiler.h"
44
#include "node_buffer.h"
5+
#include "req-wrap-inl.h"
6+
#include "node_platform.h"
57

68
#if defined(_MSC_VER)
79
#define getpid GetCurrentProcessId
@@ -17,10 +19,62 @@ namespace node {
1719
using v8::Context;
1820
using v8::FunctionTemplate;
1921
using v8::HandleScope;
22+
using v8::Isolate;
2023
using v8::Local;
2124
using v8::Message;
25+
using v8::Private;
2226
using v8::StackFrame;
2327
using v8::StackTrace;
28+
using v8::String;
29+
30+
IsolateData::IsolateData(Isolate* isolate,
31+
uv_loop_t* event_loop,
32+
MultiIsolatePlatform* platform,
33+
uint32_t* zero_fill_field) :
34+
35+
// Create string and private symbol properties as internalized one byte strings.
36+
//
37+
// Internalized because it makes property lookups a little faster and because
38+
// the string is created in the old space straight away. It's going to end up
39+
// in the old space sooner or later anyway but now it doesn't go through
40+
// v8::Eternal's new space handling first.
41+
//
42+
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
43+
// decoding step. It's a one-time cost, but why pay it when you don't have to?
44+
#define V(PropertyName, StringValue) \
45+
PropertyName ## _( \
46+
isolate, \
47+
Private::New( \
48+
isolate, \
49+
String::NewFromOneByte( \
50+
isolate, \
51+
reinterpret_cast<const uint8_t*>(StringValue), \
52+
v8::NewStringType::kInternalized, \
53+
sizeof(StringValue) - 1).ToLocalChecked())),
54+
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
55+
#undef V
56+
#define V(PropertyName, StringValue) \
57+
PropertyName ## _( \
58+
isolate, \
59+
String::NewFromOneByte( \
60+
isolate, \
61+
reinterpret_cast<const uint8_t*>(StringValue), \
62+
v8::NewStringType::kInternalized, \
63+
sizeof(StringValue) - 1).ToLocalChecked()),
64+
PER_ISOLATE_STRING_PROPERTIES(V)
65+
#undef V
66+
isolate_(isolate),
67+
event_loop_(event_loop),
68+
zero_fill_field_(zero_fill_field),
69+
platform_(platform) {
70+
if (platform_ != nullptr)
71+
platform_->RegisterIsolate(this, event_loop);
72+
}
73+
74+
IsolateData::~IsolateData() {
75+
if (platform_ != nullptr)
76+
platform_->UnregisterIsolate(this);
77+
}
2478

2579
void Environment::Start(int argc,
2680
const char* const* argv,

src/env.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,13 @@ struct node_async_ids {
341341

342342
class IsolateData {
343343
public:
344-
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
345-
uint32_t* zero_fill_field = nullptr);
344+
IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
345+
MultiIsolatePlatform* platform = nullptr,
346+
uint32_t* zero_fill_field = nullptr);
347+
~IsolateData();
346348
inline uv_loop_t* event_loop() const;
347349
inline uint32_t* zero_fill_field() const;
350+
inline MultiIsolatePlatform* platform() const;
348351

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

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

361365
private:
362366
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
@@ -369,8 +373,10 @@ class IsolateData {
369373
#undef VS
370374
#undef VP
371375

376+
v8::Isolate* const isolate_;
372377
uv_loop_t* const event_loop_;
373378
uint32_t* const zero_fill_field_;
379+
MultiIsolatePlatform* platform_;
374380

375381
DISALLOW_COPY_AND_ASSIGN(IsolateData);
376382
};

src/inspector_agent.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class NodeInspectorClient : public V8InspectorClient {
309309
terminated_ = false;
310310
running_nested_loop_ = true;
311311
while (!terminated_ && channel_->waitForFrontendMessage()) {
312-
platform_->FlushForegroundTasksInternal();
312+
platform_->FlushForegroundTasks(env_->isolate());
313313
}
314314
terminated_ = false;
315315
running_nested_loop_ = false;

src/node.cc

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ node::DebugOptions debug_options;
262262

263263
static struct {
264264
#if NODE_USE_V8_PLATFORM
265-
void Initialize(int thread_pool_size, uv_loop_t* loop) {
265+
void Initialize(int thread_pool_size) {
266266
tracing_agent_ =
267267
trace_enabled ? new tracing::Agent() : nullptr;
268-
platform_ = new NodePlatform(thread_pool_size, loop,
268+
platform_ = new NodePlatform(thread_pool_size,
269269
trace_enabled ? tracing_agent_->GetTracingController() : nullptr);
270270
V8::InitializePlatform(platform_);
271271
tracing::TraceEventHelper::SetTracingController(
@@ -280,8 +280,8 @@ static struct {
280280
tracing_agent_ = nullptr;
281281
}
282282

283-
void DrainVMTasks() {
284-
platform_->DrainBackgroundTasks();
283+
void DrainVMTasks(Isolate* isolate) {
284+
platform_->DrainBackgroundTasks(isolate);
285285
}
286286

287287
#if HAVE_INSPECTOR
@@ -306,12 +306,16 @@ static struct {
306306
tracing_agent_->Stop();
307307
}
308308

309+
NodePlatform* Platform() {
310+
return platform_;
311+
}
312+
309313
tracing::Agent* tracing_agent_;
310314
NodePlatform* platform_;
311315
#else // !NODE_USE_V8_PLATFORM
312-
void Initialize(int thread_pool_size, uv_loop_t* loop) {}
316+
void Initialize(int thread_pool_size) {}
313317
void Dispose() {}
314-
void DrainVMTasks() {}
318+
void DrainVMTasks(Isolate* isolate) {}
315319
bool StartInspector(Environment *env, const char* script_path,
316320
const node::DebugOptions& options) {
317321
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
@@ -323,6 +327,10 @@ static struct {
323327
"so event tracing is not available.\n");
324328
}
325329
void StopTracingAgent() {}
330+
331+
NodePlatform* Platform() {
332+
return nullptr;
333+
}
326334
#endif // !NODE_USE_V8_PLATFORM
327335

328336
#if !NODE_USE_V8_PLATFORM || !HAVE_INSPECTOR
@@ -4431,7 +4439,14 @@ int EmitExit(Environment* env) {
44314439

44324440

44334441
IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) {
4434-
return new IsolateData(isolate, loop);
4442+
return new IsolateData(isolate, loop, nullptr);
4443+
}
4444+
4445+
IsolateData* CreateIsolateData(
4446+
Isolate* isolate,
4447+
uv_loop_t* loop,
4448+
MultiIsolatePlatform* platform) {
4449+
return new IsolateData(isolate, loop, platform);
44354450
}
44364451

44374452

@@ -4516,7 +4531,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
45164531
do {
45174532
uv_run(env.event_loop(), UV_RUN_DEFAULT);
45184533

4519-
v8_platform.DrainVMTasks();
4534+
v8_platform.DrainVMTasks(isolate);
45204535

45214536
more = uv_loop_alive(env.event_loop());
45224537
if (more)
@@ -4537,7 +4552,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
45374552
RunAtExit(&env);
45384553
uv_key_delete(&thread_local_env);
45394554

4540-
v8_platform.DrainVMTasks();
4555+
v8_platform.DrainVMTasks(isolate);
45414556
WaitForInspectorDisconnect(&env);
45424557
#if defined(LEAK_SANITIZER)
45434558
__lsan_do_leak_check();
@@ -4580,7 +4595,11 @@ inline int Start(uv_loop_t* event_loop,
45804595
Locker locker(isolate);
45814596
Isolate::Scope isolate_scope(isolate);
45824597
HandleScope handle_scope(isolate);
4583-
IsolateData isolate_data(isolate, event_loop, allocator.zero_fill_field());
4598+
IsolateData isolate_data(
4599+
isolate,
4600+
event_loop,
4601+
v8_platform.Platform(),
4602+
allocator.zero_fill_field());
45844603
exit_code = Start(isolate, &isolate_data, argc, argv, exec_argc, exec_argv);
45854604
}
45864605

@@ -4627,7 +4646,7 @@ int Start(int argc, char** argv) {
46274646
V8::SetEntropySource(crypto::EntropySource);
46284647
#endif // HAVE_OPENSSL
46294648

4630-
v8_platform.Initialize(v8_thread_pool_size, uv_default_loop());
4649+
v8_platform.Initialize(v8_thread_pool_size);
46314650
// Enable tracing when argv has --trace-events-enabled.
46324651
if (trace_enabled) {
46334652
fprintf(stderr, "Warning: Trace event is an experimental feature "

src/node.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#endif
6262

6363
#include "v8.h" // NOLINT(build/include_order)
64+
#include "v8-platform.h" // NOLINT(build/include_order)
6465
#include "node_version.h" // NODE_MODULE_VERSION
6566

6667
#define NODE_MAKE_VERSION(major, minor, patch) \
@@ -209,8 +210,27 @@ NODE_EXTERN void Init(int* argc,
209210
class IsolateData;
210211
class Environment;
211212

212-
NODE_EXTERN IsolateData* CreateIsolateData(v8::Isolate* isolate,
213-
struct uv_loop_s* loop);
213+
class MultiIsolatePlatform : public v8::Platform {
214+
public:
215+
virtual ~MultiIsolatePlatform() { }
216+
virtual void DrainBackgroundTasks(v8::Isolate* isolate) = 0;
217+
218+
// These will be called by the `IsolateData` creation/destruction functions.
219+
virtual void RegisterIsolate(IsolateData* isolate_data,
220+
struct uv_loop_s* loop) = 0;
221+
virtual void UnregisterIsolate(IsolateData* isolate_data) = 0;
222+
};
223+
224+
// If `platform` is passed, it will be used to register new Worker instances.
225+
// It can be `nullptr`, in which case creating new Workers inside of
226+
// Environments that use this `IsolateData` will not work.
227+
NODE_EXTERN IsolateData* CreateIsolateData(
228+
v8::Isolate* isolate,
229+
struct uv_loop_s* loop);
230+
NODE_EXTERN IsolateData* CreateIsolateData(
231+
v8::Isolate* isolate,
232+
struct uv_loop_s* loop,
233+
MultiIsolatePlatform* platform);
214234
NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
215235

216236
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,

0 commit comments

Comments
 (0)