Skip to content

Commit 04713b9

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: nodejs#30044
1 parent 5175f64 commit 04713b9

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
@@ -153,7 +153,6 @@ constexpr size_t kFsStatsBufferLength =
153153
V(contextify_global_private_symbol, "node:contextify:global") \
154154
V(decorated_private_symbol, "node:decorated") \
155155
V(napi_wrapper, "node:napi:wrapper") \
156-
V(sab_lifetimepartner_symbol, "node:sharedArrayBufferLifetimePartner") \
157156

158157
// Symbols are per-isolate primitives but Environment proxies them
159158
// for the sake of convenience.
@@ -1255,10 +1254,6 @@ class Environment : public MemoryRetainer {
12551254

12561255
#endif // HAVE_INSPECTOR
12571256

1258-
// Only available if a MultiIsolatePlatform is in use.
1259-
void AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose(
1260-
std::shared_ptr<v8::ArrayBuffer::Allocator>);
1261-
12621257
private:
12631258
template <typename Fn>
12641259
inline void CreateImmediate(Fn&& cb,
@@ -1435,10 +1430,6 @@ class Environment : public MemoryRetainer {
14351430
// Used by embedders to shutdown running Node instance.
14361431
AsyncRequest thread_stopper_;
14371432

1438-
typedef std::unordered_set<std::shared_ptr<v8::ArrayBuffer::Allocator>>
1439-
ArrayBufferAllocatorList;
1440-
ArrayBufferAllocatorList* keep_alive_allocators_ = nullptr;
1441-
14421433
template <typename T>
14431434
void ForEachBaseObject(T&& iterator);
14441435

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::Context;
1717
using v8::EscapableHandleScope;
1818
using v8::Exception;
@@ -123,10 +123,9 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
123123
std::vector<Local<SharedArrayBuffer>> shared_array_buffers;
124124
// Attach all transferred SharedArrayBuffers to their new Isolate.
125125
for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) {
126-
Local<SharedArrayBuffer> sab;
127-
if (!shared_array_buffers_[i]->GetSharedArrayBuffer(env, context)
128-
.ToLocal(&sab))
129-
return MaybeLocal<Value>();
126+
Local<SharedArrayBuffer> sab =
127+
SharedArrayBuffer::New(env->isolate(),
128+
std::move(shared_array_buffers_[i]));
130129
shared_array_buffers.push_back(sab);
131130
}
132131
shared_array_buffers_.clear();
@@ -141,30 +140,12 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
141140
delegate.deserializer = &deserializer;
142141

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

169150
if (deserializer.ReadHeader(context).IsNothing())
170151
return MaybeLocal<Value>();
@@ -173,8 +154,8 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
173154
}
174155

175156
void Message::AddSharedArrayBuffer(
176-
const SharedArrayBufferMetadataReference& reference) {
177-
shared_array_buffers_.push_back(reference);
157+
std::shared_ptr<BackingStore> backing_store) {
158+
shared_array_buffers_.emplace_back(std::move(backing_store));
178159
}
179160

180161
void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) {
@@ -249,16 +230,9 @@ class SerializerDelegate : public ValueSerializer::Delegate {
249230
}
250231
}
251232

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

@@ -386,18 +360,12 @@ Maybe<bool> Message::Serialize(Environment* env,
386360
}
387361

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

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

403371
delegate.Finish();
@@ -411,9 +379,8 @@ Maybe<bool> Message::Serialize(Environment* env,
411379
}
412380

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

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::WasmModuleObject::TransferrableModule> 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_));

0 commit comments

Comments
 (0)