Skip to content

Commit 37a60a8

Browse files
addaleaxMylesBorins
authored andcommitted
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. Original-PR-URL: ayojs/ayo#89 Original-Reviewed-By: Timothy Gu <[email protected]> PR-URL: #16700 Reviewed-By: James M Snell <[email protected]>
1 parent 121245f commit 37a60a8

10 files changed

+267
-93
lines changed

src/env-inl.h

+7-35
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

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

2476
void Environment::Start(int argc,
2577
const char* const* argv,

src/env.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,13 @@ struct node_async_ids {
344344

345345
class IsolateData {
346346
public:
347-
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
348-
uint32_t* zero_fill_field = nullptr);
347+
IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
348+
MultiIsolatePlatform* platform = nullptr,
349+
uint32_t* zero_fill_field = nullptr);
350+
~IsolateData();
349351
inline uv_loop_t* event_loop() const;
350352
inline uint32_t* zero_fill_field() const;
353+
inline MultiIsolatePlatform* platform() const;
351354

352355
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
353356
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
@@ -360,6 +363,7 @@ class IsolateData {
360363
#undef VP
361364

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

364368
private:
365369
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
@@ -372,8 +376,10 @@ class IsolateData {
372376
#undef VS
373377
#undef VP
374378

379+
v8::Isolate* const isolate_;
375380
uv_loop_t* const event_loop_;
376381
uint32_t* const zero_fill_field_;
382+
MultiIsolatePlatform* platform_;
377383

378384
DISALLOW_COPY_AND_ASSIGN(IsolateData);
379385
};

src/inspector_agent.cc

+1-1
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

+30-11
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
@@ -4769,7 +4777,14 @@ int EmitExit(Environment* env) {
47694777

47704778

47714779
IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) {
4772-
return new IsolateData(isolate, loop);
4780+
return new IsolateData(isolate, loop, nullptr);
4781+
}
4782+
4783+
IsolateData* CreateIsolateData(
4784+
Isolate* isolate,
4785+
uv_loop_t* loop,
4786+
MultiIsolatePlatform* platform) {
4787+
return new IsolateData(isolate, loop, platform);
47734788
}
47744789

47754790

@@ -4854,7 +4869,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
48544869
do {
48554870
uv_run(env.event_loop(), UV_RUN_DEFAULT);
48564871

4857-
v8_platform.DrainVMTasks();
4872+
v8_platform.DrainVMTasks(isolate);
48584873

48594874
more = uv_loop_alive(env.event_loop());
48604875
if (more)
@@ -4875,7 +4890,7 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
48754890
RunAtExit(&env);
48764891
uv_key_delete(&thread_local_env);
48774892

4878-
v8_platform.DrainVMTasks();
4893+
v8_platform.DrainVMTasks(isolate);
48794894
WaitForInspectorDisconnect(&env);
48804895
#if defined(LEAK_SANITIZER)
48814896
__lsan_do_leak_check();
@@ -4918,7 +4933,11 @@ inline int Start(uv_loop_t* event_loop,
49184933
Locker locker(isolate);
49194934
Isolate::Scope isolate_scope(isolate);
49204935
HandleScope handle_scope(isolate);
4921-
IsolateData isolate_data(isolate, event_loop, allocator.zero_fill_field());
4936+
IsolateData isolate_data(
4937+
isolate,
4938+
event_loop,
4939+
v8_platform.Platform(),
4940+
allocator.zero_fill_field());
49224941
exit_code = Start(isolate, &isolate_data, argc, argv, exec_argc, exec_argv);
49234942
}
49244943

@@ -4965,7 +4984,7 @@ int Start(int argc, char** argv) {
49654984
V8::SetEntropySource(crypto::EntropySource);
49664985
#endif // HAVE_OPENSSL
49674986

4968-
v8_platform.Initialize(v8_thread_pool_size, uv_default_loop());
4987+
v8_platform.Initialize(v8_thread_pool_size);
49694988
// Enable tracing when argv has --trace-events-enabled.
49704989
if (trace_enabled) {
49714990
fprintf(stderr, "Warning: Trace event is an experimental feature "

src/node.h

+22-2
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)