Skip to content

Commit fc885d6

Browse files
addaleaxtargos
authored andcommitted
src: remove custom tracking for SharedArrayBuffers
Remove custom tracking for `SharedArrayBuffer`s and their allocators and instead let V8 do the tracking of both. This is required starting in V8 7.9, because lifetime management for `ArrayBuffer::Allocator`s differs from what was performed previously (i.e. it is no longer easily possible for one Isolate to release an `ArrayBuffer` and another to accept it into its own allocator), and the alternative would have been adapting the `SharedArrayBuffer` tracking logic to also apply to regular `ArrayBuffer` instances. Refs: #30044
1 parent 09bc6e5 commit fc885d6

13 files changed

+58
-335
lines changed

node.gyp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,6 @@
562562
'src/node_zlib.cc',
563563
'src/pipe_wrap.cc',
564564
'src/process_wrap.cc',
565-
'src/sharedarraybuffer_metadata.cc',
566565
'src/signal_wrap.cc',
567566
'src/spawn_sync.cc',
568567
'src/stream_base.cc',
@@ -640,7 +639,6 @@
640639
'src/pipe_wrap.h',
641640
'src/req_wrap.h',
642641
'src/req_wrap-inl.h',
643-
'src/sharedarraybuffer_metadata.h',
644642
'src/spawn_sync.h',
645643
'src/stream_base.h',
646644
'src/stream_base-inl.h',

src/api/environment.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,14 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator,
259259
return NewIsolate(&params, event_loop, platform);
260260
}
261261

262+
Isolate* NewIsolate(std::shared_ptr<ArrayBufferAllocator> allocator,
263+
uv_loop_t* event_loop,
264+
MultiIsolatePlatform* platform) {
265+
Isolate::CreateParams params;
266+
if (allocator) params.array_buffer_allocator_shared = allocator;
267+
return NewIsolate(&params, event_loop, platform);
268+
}
269+
262270
IsolateData* CreateIsolateData(Isolate* isolate,
263271
uv_loop_t* loop,
264272
MultiIsolatePlatform* platform,

src/env.cc

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,21 +1037,6 @@ char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
10371037
return new_data;
10381038
}
10391039

1040-
void Environment::AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
1041-
std::shared_ptr<v8::ArrayBuffer::Allocator> allocator) {
1042-
if (keep_alive_allocators_ == nullptr) {
1043-
MultiIsolatePlatform* platform = isolate_data()->platform();
1044-
CHECK_NOT_NULL(platform);
1045-
1046-
keep_alive_allocators_ = new ArrayBufferAllocatorList();
1047-
platform->AddIsolateFinishedCallback(isolate(), [](void* data) {
1048-
delete static_cast<ArrayBufferAllocatorList*>(data);
1049-
}, static_cast<void*>(keep_alive_allocators_));
1050-
}
1051-
1052-
keep_alive_allocators_->insert(allocator);
1053-
}
1054-
10551040
bool Environment::RunWeakRefCleanup() {
10561041
isolate()->ClearKeptObjects();
10571042

src/env.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ constexpr size_t kFsStatsBufferLength =
156156
V(contextify_global_private_symbol, "node:contextify:global") \
157157
V(decorated_private_symbol, "node:decorated") \
158158
V(napi_wrapper, "node:napi:wrapper") \
159-
V(sab_lifetimepartner_symbol, "node:sharedArrayBufferLifetimePartner") \
160159

161160
// Symbols are per-isolate primitives but Environment proxies them
162161
// for the sake of convenience.
@@ -1258,10 +1257,6 @@ class Environment : public MemoryRetainer {
12581257

12591258
#endif // HAVE_INSPECTOR
12601259

1261-
// Only available if a MultiIsolatePlatform is in use.
1262-
void AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
1263-
std::shared_ptr<v8::ArrayBuffer::Allocator>);
1264-
12651260
private:
12661261
template <typename Fn>
12671262
inline void CreateImmediate(Fn&& cb,
@@ -1438,10 +1433,6 @@ class Environment : public MemoryRetainer {
14381433
// Used by embedders to shutdown running Node instance.
14391434
AsyncRequest thread_stopper_;
14401435

1441-
typedef std::unordered_set<std::shared_ptr<v8::ArrayBuffer::Allocator>>
1442-
ArrayBufferAllocatorList;
1443-
ArrayBufferAllocatorList* keep_alive_allocators_ = nullptr;
1444-
14451436
template <typename T>
14461437
void ForEachBaseObject(T&& iterator);
14471438

src/memory_tracker-inl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ void MemoryTracker::TrackField(const char* edge_name,
109109
TrackField(edge_name, value.get(), node_name);
110110
}
111111

112+
template <typename T>
113+
void MemoryTracker::TrackField(const char* edge_name,
114+
const std::shared_ptr<T>& value,
115+
const char* node_name) {
116+
if (value.get() == nullptr) {
117+
return;
118+
}
119+
TrackField(edge_name, value.get(), node_name);
120+
}
121+
112122
template <typename T, typename Iterator>
113123
void MemoryTracker::TrackField(const char* edge_name,
114124
const T& value,
@@ -206,6 +216,12 @@ void MemoryTracker::TrackField(const char* edge_name,
206216
TrackFieldWithSize(edge_name, value.size, "MallocedBuffer");
207217
}
208218

219+
void MemoryTracker::TrackField(const char* edge_name,
220+
const v8::BackingStore* value,
221+
const char* node_name) {
222+
TrackFieldWithSize(edge_name, value->ByteLength(), "BackingStore");
223+
}
224+
209225
void MemoryTracker::TrackField(const char* name,
210226
const uv_buf_t& value,
211227
const char* node_name) {

src/memory_tracker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class MemoryTracker {
138138
inline void TrackField(const char* edge_name,
139139
const std::unique_ptr<T>& value,
140140
const char* node_name = nullptr);
141+
template <typename T>
142+
inline void TrackField(const char* edge_name,
143+
const std::shared_ptr<T>& value,
144+
const char* node_name = nullptr);
141145

142146
// For containers, the elements will be graphed as grandchildren nodes
143147
// if the container is not empty.
@@ -197,6 +201,9 @@ class MemoryTracker {
197201
inline void TrackField(const char* edge_name,
198202
const MallocedBuffer<T>& value,
199203
const char* node_name = nullptr);
204+
inline void TrackField(const char* edge_name,
205+
const v8::BackingStore* value,
206+
const char* node_name = nullptr);
200207
// We do not implement CleanupHookCallback as MemoryRetainer
201208
// but instead specialize the method here to avoid the cost of
202209
// virtual pointers.

src/node.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ NODE_EXTERN v8::Isolate* NewIsolate(ArrayBufferAllocator* allocator,
303303
NODE_EXTERN v8::Isolate* NewIsolate(ArrayBufferAllocator* allocator,
304304
struct uv_loop_s* event_loop,
305305
MultiIsolatePlatform* platform);
306+
NODE_EXTERN v8::Isolate* NewIsolate(
307+
std::shared_ptr<ArrayBufferAllocator> allocator,
308+
struct uv_loop_s* event_loop,
309+
MultiIsolatePlatform* platform);
306310

307311
// Creates a new context with Node.js-specific tweaks.
308312
NODE_EXTERN v8::Local<v8::Context> NewContext(

src/node_messaging.cc

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
using node::contextify::ContextifyContext;
1313
using v8::Array;
1414
using v8::ArrayBuffer;
15-
using v8::ArrayBufferCreationMode;
15+
using v8::BackingStore;
1616
using v8::CompiledWasmModule;
1717
using v8::Context;
1818
using v8::EscapableHandleScope;
@@ -124,10 +124,9 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
124124
std::vector<Local<SharedArrayBuffer>> shared_array_buffers;
125125
// Attach all transferred SharedArrayBuffers to their new Isolate.
126126
for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) {
127-
Local<SharedArrayBuffer> sab;
128-
if (!shared_array_buffers_[i]->GetSharedArrayBuffer(env, context)
129-
.ToLocal(&sab))
130-
return MaybeLocal<Value>();
127+
Local<SharedArrayBuffer> sab =
128+
SharedArrayBuffer::New(env->isolate(),
129+
std::move(shared_array_buffers_[i]));
131130
shared_array_buffers.push_back(sab);
132131
}
133132
shared_array_buffers_.clear();
@@ -142,30 +141,12 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
142141
delegate.deserializer = &deserializer;
143142

144143
// Attach all transferred ArrayBuffers to their new Isolate.
145-
for (uint32_t i = 0; i < array_buffer_contents_.size(); ++i) {
146-
if (!env->isolate_data()->uses_node_allocator()) {
147-
// We don't use Node's allocator on the receiving side, so we have
148-
// to create the ArrayBuffer from a copy of the memory.
149-
AllocatedBuffer buf =
150-
env->AllocateManaged(array_buffer_contents_[i].size);
151-
memcpy(buf.data(),
152-
array_buffer_contents_[i].data,
153-
array_buffer_contents_[i].size);
154-
deserializer.TransferArrayBuffer(i, buf.ToArrayBuffer());
155-
continue;
156-
}
157-
158-
env->isolate_data()->node_allocator()->RegisterPointer(
159-
array_buffer_contents_[i].data, array_buffer_contents_[i].size);
160-
144+
for (uint32_t i = 0; i < array_buffers_.size(); ++i) {
161145
Local<ArrayBuffer> ab =
162-
ArrayBuffer::New(env->isolate(),
163-
array_buffer_contents_[i].release(),
164-
array_buffer_contents_[i].size,
165-
ArrayBufferCreationMode::kInternalized);
146+
ArrayBuffer::New(env->isolate(), std::move(array_buffers_[i]));
166147
deserializer.TransferArrayBuffer(i, ab);
167148
}
168-
array_buffer_contents_.clear();
149+
array_buffers_.clear();
169150

170151
if (deserializer.ReadHeader(context).IsNothing())
171152
return MaybeLocal<Value>();
@@ -174,8 +155,8 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
174155
}
175156

176157
void Message::AddSharedArrayBuffer(
177-
const SharedArrayBufferMetadataReference& reference) {
178-
shared_array_buffers_.push_back(reference);
158+
std::shared_ptr<BackingStore> backing_store) {
159+
shared_array_buffers_.emplace_back(std::move(backing_store));
179160
}
180161

181162
void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) {
@@ -250,16 +231,9 @@ class SerializerDelegate : public ValueSerializer::Delegate {
250231
}
251232
}
252233

253-
auto reference = SharedArrayBufferMetadata::ForSharedArrayBuffer(
254-
env_,
255-
context_,
256-
shared_array_buffer);
257-
if (!reference) {
258-
return Nothing<uint32_t>();
259-
}
260234
seen_shared_array_buffers_.emplace_back(
261235
Global<SharedArrayBuffer> { isolate, shared_array_buffer });
262-
msg_->AddSharedArrayBuffer(reference);
236+
msg_->AddSharedArrayBuffer(shared_array_buffer->GetBackingStore());
263237
return Just(i);
264238
}
265239

@@ -387,18 +361,12 @@ Maybe<bool> Message::Serialize(Environment* env,
387361
}
388362

389363
for (Local<ArrayBuffer> ab : array_buffers) {
390-
// If serialization succeeded, we want to take ownership of
391-
// (a.k.a. externalize) the underlying memory region and render
392-
// it inaccessible in this Isolate.
393-
ArrayBuffer::Contents contents = ab->Externalize();
364+
// If serialization succeeded, we render it inaccessible in this Isolate.
365+
std::shared_ptr<BackingStore> backing_store = ab->GetBackingStore();
366+
ab->Externalize(backing_store);
394367
ab->Detach();
395368

396-
CHECK(env->isolate_data()->uses_node_allocator());
397-
env->isolate_data()->node_allocator()->UnregisterPointer(
398-
contents.Data(), contents.ByteLength());
399-
400-
array_buffer_contents_.emplace_back(MallocedBuffer<char>{
401-
static_cast<char*>(contents.Data()), contents.ByteLength()});
369+
array_buffers_.emplace_back(std::move(backing_store));
402370
}
403371

404372
delegate.Finish();
@@ -412,9 +380,8 @@ Maybe<bool> Message::Serialize(Environment* env,
412380
}
413381

414382
void Message::MemoryInfo(MemoryTracker* tracker) const {
415-
tracker->TrackField("array_buffer_contents", array_buffer_contents_);
416-
tracker->TrackFieldWithSize("shared_array_buffers",
417-
shared_array_buffers_.size() * sizeof(shared_array_buffers_[0]));
383+
tracker->TrackField("array_buffers_", array_buffers_);
384+
tracker->TrackField("shared_array_buffers", shared_array_buffers_);
418385
tracker->TrackField("message_ports", message_ports_);
419386
}
420387

src/node_messaging.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include "env.h"
77
#include "node_mutex.h"
8-
#include "sharedarraybuffer_metadata.h"
98
#include <list>
109

1110
namespace node {
@@ -52,7 +51,7 @@ class Message : public MemoryRetainer {
5251

5352
// Internal method of Message that is called when a new SharedArrayBuffer
5453
// object is encountered in the incoming value's structure.
55-
void AddSharedArrayBuffer(const SharedArrayBufferMetadataReference& ref);
54+
void AddSharedArrayBuffer(std::shared_ptr<v8::BackingStore> backing_store);
5655
// Internal method of Message that is called once serialization finishes
5756
// and that transfers ownership of `data` to this message.
5857
void AddMessagePort(std::unique_ptr<MessagePortData>&& data);
@@ -74,8 +73,8 @@ class Message : public MemoryRetainer {
7473

7574
private:
7675
MallocedBuffer<char> main_message_buf_;
77-
std::vector<MallocedBuffer<char>> array_buffer_contents_;
78-
std::vector<SharedArrayBufferMetadataReference> shared_array_buffers_;
76+
std::vector<std::shared_ptr<v8::BackingStore>> array_buffers_;
77+
std::vector<std::shared_ptr<v8::BackingStore>> shared_array_buffers_;
7978
std::vector<std::unique_ptr<MessagePortData>> message_ports_;
8079
std::vector<v8::CompiledWasmModule> wasm_modules_;
8180

src/node_worker.cc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ Worker::Worker(Environment* env,
5757
per_isolate_opts_(per_isolate_opts),
5858
exec_argv_(exec_argv),
5959
platform_(env->isolate_data()->platform()),
60-
array_buffer_allocator_(ArrayBufferAllocator::Create()),
6160
start_profiler_idle_notifier_(env->profiler_idle_notifier_started()),
6261
thread_id_(Environment::AllocateThreadId()),
6362
env_vars_(env->env_vars()) {
@@ -101,10 +100,6 @@ bool Worker::is_stopped() const {
101100
return stopped_;
102101
}
103102

104-
std::shared_ptr<ArrayBufferAllocator> Worker::array_buffer_allocator() {
105-
return array_buffer_allocator_;
106-
}
107-
108103
// This class contains data that is only relevant to the child thread itself,
109104
// and only while it is running.
110105
// (Eventually, the Environment instance should probably also be moved here.)
@@ -114,8 +109,10 @@ class WorkerThreadData {
114109
: w_(w) {
115110
CHECK_EQ(uv_loop_init(&loop_), 0);
116111

112+
std::shared_ptr<ArrayBufferAllocator> allocator =
113+
ArrayBufferAllocator::Create();
117114
Isolate* isolate = NewIsolate(
118-
w->array_buffer_allocator_.get(),
115+
allocator,
119116
&loop_,
120117
w->platform_);
121118
CHECK_NOT_NULL(isolate);
@@ -129,7 +126,7 @@ class WorkerThreadData {
129126
isolate_data_.reset(CreateIsolateData(isolate,
130127
&loop_,
131128
w_->platform_,
132-
w->array_buffer_allocator_.get()));
129+
allocator.get()));
133130
CHECK(isolate_data_);
134131
if (w_->per_isolate_opts_)
135132
isolate_data_->set_options(std::move(w_->per_isolate_opts_));

src/node_worker.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class Worker : public AsyncWrap {
4141
SET_SELF_SIZE(Worker)
4242

4343
bool is_stopped() const;
44-
std::shared_ptr<ArrayBufferAllocator> array_buffer_allocator();
4544

4645
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
4746
static void CloneParentEnvVars(
@@ -60,7 +59,6 @@ class Worker : public AsyncWrap {
6059
std::vector<std::string> argv_;
6160

6261
MultiIsolatePlatform* platform_;
63-
std::shared_ptr<ArrayBufferAllocator> array_buffer_allocator_;
6462
v8::Isolate* isolate_ = nullptr;
6563
bool start_profiler_idle_notifier_;
6664
uv_thread_t tid_;

0 commit comments

Comments
 (0)