@@ -36,6 +36,19 @@ using v8::ValueSerializer;
36
36
using v8::WasmModuleObject;
37
37
38
38
namespace node {
39
+
40
+ BaseObject::TransferMode BaseObject::GetTransferMode () const {
41
+ return BaseObject::TransferMode::kUntransferable ;
42
+ }
43
+
44
+ std::unique_ptr<worker::TransferData> BaseObject::TransferForMessaging () {
45
+ return CloneForMessaging ();
46
+ }
47
+
48
+ std::unique_ptr<worker::TransferData> BaseObject::CloneForMessaging () const {
49
+ return {};
50
+ }
51
+
39
52
namespace worker {
40
53
41
54
Message::Message (MallocedBuffer<char >&& buffer)
@@ -54,21 +67,20 @@ class DeserializerDelegate : public ValueDeserializer::Delegate {
54
67
DeserializerDelegate (
55
68
Message* m,
56
69
Environment* env,
57
- const std::vector<MessagePort*>& message_ports ,
70
+ const std::vector<BaseObjectPtr<BaseObject>>& host_objects ,
58
71
const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers,
59
72
const std::vector<WasmModuleObject::TransferrableModule>& wasm_modules)
60
- : message_ports_(message_ports ),
73
+ : host_objects_(host_objects ),
61
74
shared_array_buffers_ (shared_array_buffers),
62
75
wasm_modules_(wasm_modules) {}
63
76
64
77
MaybeLocal<Object> ReadHostObject (Isolate* isolate) override {
65
- // Currently, only MessagePort hosts objects are supported, so identifying
66
- // by the index in the message's MessagePort array is sufficient.
78
+ // Identifying the index in the message's BaseObject array is sufficient.
67
79
uint32_t id;
68
80
if (!deserializer->ReadUint32 (&id))
69
81
return MaybeLocal<Object>();
70
- CHECK_LE (id, message_ports_ .size ());
71
- return message_ports_ [id]->object (isolate);
82
+ CHECK_LE (id, host_objects_ .size ());
83
+ return host_objects_ [id]->object (isolate);
72
84
}
73
85
74
86
MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId (
@@ -87,7 +99,7 @@ class DeserializerDelegate : public ValueDeserializer::Delegate {
87
99
ValueDeserializer* deserializer = nullptr ;
88
100
89
101
private:
90
- const std::vector<MessagePort*>& message_ports_ ;
102
+ const std::vector<BaseObjectPtr<BaseObject>>& host_objects_ ;
91
103
const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers_;
92
104
const std::vector<WasmModuleObject::TransferrableModule>& wasm_modules_;
93
105
};
@@ -101,22 +113,25 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
101
113
EscapableHandleScope handle_scope (env->isolate ());
102
114
Context::Scope context_scope (context);
103
115
104
- // Create all necessary MessagePort handles.
105
- std::vector<MessagePort*> ports (message_ports_.size ());
106
- for (uint32_t i = 0 ; i < message_ports_.size (); ++i) {
107
- ports[i] = MessagePort::New (env,
108
- context,
109
- std::move (message_ports_[i]));
110
- if (ports[i] == nullptr ) {
111
- for (MessagePort* port : ports) {
112
- // This will eventually release the MessagePort object itself.
113
- if (port != nullptr )
114
- port->Close ();
116
+ // Create all necessary objects for transferables, e.g. MessagePort handles.
117
+ std::vector<BaseObjectPtr<BaseObject>> host_objects (transferables_.size ());
118
+ for (uint32_t i = 0 ; i < transferables_.size (); ++i) {
119
+ TransferData* data = transferables_[i].get ();
120
+ host_objects[i] = data->Deserialize (
121
+ env, context, std::move (transferables_[i]));
122
+ if (!host_objects[i]) {
123
+ for (BaseObjectPtr<BaseObject> object : host_objects) {
124
+ if (!object) continue ;
125
+
126
+ // Since creating one of the objects failed, we don't want to have the
127
+ // other objects lying around in memory. We act as if the object has
128
+ // been garbage-collected.
129
+ object->Detach ();
115
130
}
116
131
return MaybeLocal<Value>();
117
132
}
118
133
}
119
- message_ports_ .clear ();
134
+ transferables_ .clear ();
120
135
121
136
std::vector<Local<SharedArrayBuffer>> shared_array_buffers;
122
137
// Attach all transferred SharedArrayBuffers to their new Isolate.
@@ -130,7 +145,7 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
130
145
shared_array_buffers_.clear ();
131
146
132
147
DeserializerDelegate delegate (
133
- this , env, ports , shared_array_buffers, wasm_modules_);
148
+ this , env, host_objects , shared_array_buffers, wasm_modules_);
134
149
ValueDeserializer deserializer (
135
150
env->isolate (),
136
151
reinterpret_cast <const uint8_t *>(main_message_buf_.data ),
@@ -175,8 +190,8 @@ void Message::AddSharedArrayBuffer(
175
190
shared_array_buffers_.push_back (reference);
176
191
}
177
192
178
- void Message::AddMessagePort (std::unique_ptr<MessagePortData >&& data) {
179
- message_ports_ .emplace_back (std::move (data));
193
+ void Message::AddTransferable (std::unique_ptr<TransferData >&& data) {
194
+ transferables_ .emplace_back (std::move (data));
180
195
}
181
196
182
197
uint32_t Message::AddWASMModule (WasmModuleObject::TransferrableModule&& mod) {
@@ -242,8 +257,8 @@ class SerializerDelegate : public ValueSerializer::Delegate {
242
257
}
243
258
244
259
Maybe<bool > WriteHostObject (Isolate* isolate, Local<Object> object) override {
245
- if (env_->message_port_constructor_template ()->HasInstance (object)) {
246
- return WriteMessagePort (Unwrap<MessagePort >(object));
260
+ if (env_->base_object_ctor_template ()->HasInstance (object)) {
261
+ return WriteHostObject (Unwrap<BaseObject >(object));
247
262
}
248
263
249
264
ThrowDataCloneError (env_->clone_unsupported_type_str ());
@@ -282,32 +297,61 @@ class SerializerDelegate : public ValueSerializer::Delegate {
282
297
void Finish () {
283
298
// Only close the MessagePort handles and actually transfer them
284
299
// once we know that serialization succeeded.
285
- for (MessagePort* port : ports_) {
286
- port->Close ();
287
- msg_->AddMessagePort (port->Detach ());
300
+ for (uint32_t i = 0 ; i < host_objects_.size (); i++) {
301
+ BaseObject* host_object = host_objects_[i];
302
+ std::unique_ptr<TransferData> data;
303
+ if (i < first_cloned_object_index_)
304
+ data = host_object->TransferForMessaging ();
305
+ if (!data)
306
+ data = host_object->CloneForMessaging ();
307
+ CHECK (data);
308
+ msg_->AddTransferable (std::move (data));
288
309
}
289
310
}
290
311
312
+ inline void AddHostObject (BaseObject* host_object) {
313
+ // Make sure we have not started serializing the value itself yet.
314
+ CHECK_EQ (first_cloned_object_index_, SIZE_MAX);
315
+ host_objects_.push_back (host_object);
316
+ }
317
+
291
318
ValueSerializer* serializer = nullptr ;
292
319
293
320
private:
294
- Maybe<bool > WriteMessagePort (MessagePort* port ) {
295
- for (uint32_t i = 0 ; i < ports_ .size (); i++) {
296
- if (ports_ [i] == port ) {
321
+ Maybe<bool > WriteHostObject (BaseObject* host_object ) {
322
+ for (uint32_t i = 0 ; i < host_objects_ .size (); i++) {
323
+ if (host_objects_ [i] == host_object ) {
297
324
serializer->WriteUint32 (i);
298
325
return Just (true );
299
326
}
300
327
}
301
328
302
- THROW_ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST (env_);
303
- return Nothing<bool >();
329
+ BaseObject::TransferMode mode = host_object->GetTransferMode ();
330
+ if (mode == BaseObject::TransferMode::kUntransferable ) {
331
+ ThrowDataCloneError (env_->clone_unsupported_type_str ());
332
+ return Nothing<bool >();
333
+ } else if (mode == BaseObject::TransferMode::kTransferable ) {
334
+ // TODO(addaleax): This message code is too specific. Fix that in a
335
+ // semver-major follow-up.
336
+ THROW_ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST (env_);
337
+ return Nothing<bool >();
338
+ }
339
+
340
+ CHECK_EQ (mode, BaseObject::TransferMode::kCloneable );
341
+ uint32_t index = host_objects_.size ();
342
+ if (first_cloned_object_index_ == SIZE_MAX)
343
+ first_cloned_object_index_ = index ;
344
+ serializer->WriteUint32 (index );
345
+ host_objects_.push_back (host_object);
346
+ return Just (true );
304
347
}
305
348
306
349
Environment* env_;
307
350
Local<Context> context_;
308
351
Message* msg_;
309
352
std::vector<Global<SharedArrayBuffer>> seen_shared_array_buffers_;
310
- std::vector<MessagePort*> ports_;
353
+ std::vector<BaseObject*> host_objects_;
354
+ size_t first_cloned_object_index_ = SIZE_MAX;
311
355
312
356
friend class worker ::Message;
313
357
};
@@ -366,8 +410,7 @@ Maybe<bool> Message::Serialize(Environment* env,
366
410
array_buffers.push_back (ab);
367
411
serializer.TransferArrayBuffer (id, ab);
368
412
continue ;
369
- } else if (env->message_port_constructor_template ()
370
- ->HasInstance (entry)) {
413
+ } else if (env->base_object_ctor_template ()->HasInstance (entry)) {
371
414
// Check if the source MessagePort is being transferred.
372
415
if (!source_port.IsEmpty () && entry == source_port) {
373
416
ThrowDataCloneException (
@@ -376,26 +419,34 @@ Maybe<bool> Message::Serialize(Environment* env,
376
419
" Transfer list contains source port" ));
377
420
return Nothing<bool >();
378
421
}
379
- MessagePort* port = Unwrap<MessagePort>(entry.As <Object>());
380
- if (port == nullptr || port->IsDetached ()) {
422
+ BaseObject* host_object = Unwrap<BaseObject>(entry.As <Object>());
423
+ if (env->message_port_constructor_template ()->HasInstance (entry) &&
424
+ (host_object == nullptr ||
425
+ static_cast <MessagePort*>(host_object)->IsDetached ())) {
381
426
ThrowDataCloneException (
382
427
context,
383
428
FIXED_ONE_BYTE_STRING (
384
429
env->isolate (),
385
430
" MessagePort in transfer list is already detached" ));
386
431
return Nothing<bool >();
387
432
}
388
- if (std::find (delegate.ports_ .begin (), delegate.ports_ .end (), port) !=
389
- delegate.ports_ .end ()) {
433
+ if (std::find (delegate.host_objects_ .begin (),
434
+ delegate.host_objects_ .end (),
435
+ host_object) != delegate.host_objects_ .end ()) {
390
436
ThrowDataCloneException (
391
437
context,
392
- FIXED_ONE_BYTE_STRING (
393
- env->isolate (),
394
- " Transfer list contains duplicate MessagePort" ));
438
+ String::Concat (env->isolate (),
439
+ FIXED_ONE_BYTE_STRING (
440
+ env->isolate (),
441
+ " Transfer list contains duplicate " ),
442
+ entry.As <Object>()->GetConstructorName ()));
395
443
return Nothing<bool >();
396
444
}
397
- delegate.ports_ .push_back (port);
398
- continue ;
445
+ if (host_object != nullptr && host_object->GetTransferMode () !=
446
+ BaseObject::TransferMode::kUntransferable ) {
447
+ delegate.AddHostObject (host_object);
448
+ continue ;
449
+ }
399
450
}
400
451
401
452
THROW_ERR_INVALID_TRANSFER_OBJECT (env);
@@ -436,7 +487,7 @@ void Message::MemoryInfo(MemoryTracker* tracker) const {
436
487
tracker->TrackField (" array_buffer_contents" , array_buffer_contents_);
437
488
tracker->TrackFieldWithSize (" shared_array_buffers" ,
438
489
shared_array_buffers_.size () * sizeof (shared_array_buffers_[0 ]));
439
- tracker->TrackField (" message_ports " , message_ports_ );
490
+ tracker->TrackField (" transferables " , transferables_ );
440
491
}
441
492
442
493
MessagePortData::MessagePortData (MessagePort* owner) : owner_(owner) { }
@@ -702,6 +753,25 @@ std::unique_ptr<MessagePortData> MessagePort::Detach() {
702
753
return std::move (data_);
703
754
}
704
755
756
+ BaseObject::TransferMode MessagePort::GetTransferMode () const {
757
+ if (IsDetached ())
758
+ return BaseObject::TransferMode::kUntransferable ;
759
+ return BaseObject::TransferMode::kTransferable ;
760
+ }
761
+
762
+ std::unique_ptr<TransferData> MessagePort::TransferForMessaging () {
763
+ Close ();
764
+ return Detach ();
765
+ }
766
+
767
+ BaseObjectPtr<BaseObject> MessagePortData::Deserialize (
768
+ Environment* env,
769
+ Local<Context> context,
770
+ std::unique_ptr<TransferData> self) {
771
+ return BaseObjectPtr<MessagePort> { MessagePort::New (
772
+ env, context,
773
+ static_unique_pointer_cast<MessagePortData>(std::move (self))) };
774
+ }
705
775
706
776
Maybe<bool > MessagePort::PostMessage (Environment* env,
707
777
Local<Value> message_v,
@@ -729,8 +799,8 @@ Maybe<bool> MessagePort::PostMessage(Environment* env,
729
799
730
800
// Check if the target port is posted to itself.
731
801
if (data_->sibling_ != nullptr ) {
732
- for (const auto & port_data : msg.message_ports ()) {
733
- if (data_->sibling_ == port_data .get ()) {
802
+ for (const auto & transferable : msg.transferables ()) {
803
+ if (data_->sibling_ == transferable .get ()) {
734
804
doomed = true ;
735
805
ProcessEmitWarning (env, " The target port was posted to itself, and "
736
806
" the communication channel was lost" );
0 commit comments