GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_messaging.cc Lines: 725 785 92.4 %
Date: 2021-02-11 04:11:15 Branches: 358 491 72.9 %

Line Branch Exec Source
1
#include "node_messaging.h"
2
3
#include "async_wrap-inl.h"
4
#include "debug_utils-inl.h"
5
#include "memory_tracker-inl.h"
6
#include "node_buffer.h"
7
#include "node_contextify.h"
8
#include "node_errors.h"
9
#include "node_external_reference.h"
10
#include "node_process.h"
11
#include "util-inl.h"
12
13
using node::contextify::ContextifyContext;
14
using node::errors::TryCatchScope;
15
using v8::Array;
16
using v8::ArrayBuffer;
17
using v8::BackingStore;
18
using v8::CompiledWasmModule;
19
using v8::Context;
20
using v8::EscapableHandleScope;
21
using v8::Function;
22
using v8::FunctionCallbackInfo;
23
using v8::FunctionTemplate;
24
using v8::Global;
25
using v8::HandleScope;
26
using v8::Isolate;
27
using v8::Just;
28
using v8::Local;
29
using v8::Maybe;
30
using v8::MaybeLocal;
31
using v8::Nothing;
32
using v8::Object;
33
using v8::SharedArrayBuffer;
34
using v8::String;
35
using v8::Symbol;
36
using v8::Value;
37
using v8::ValueDeserializer;
38
using v8::ValueSerializer;
39
using v8::WasmModuleObject;
40
41
namespace node {
42
43
using BaseObjectList = std::vector<BaseObjectPtr<BaseObject>>;
44
45
1
BaseObject::TransferMode BaseObject::GetTransferMode() const {
46
1
  return BaseObject::TransferMode::kUntransferable;
47
}
48
49
std::unique_ptr<worker::TransferData> BaseObject::TransferForMessaging() {
50
  return CloneForMessaging();
51
}
52
53
std::unique_ptr<worker::TransferData> BaseObject::CloneForMessaging() const {
54
  return {};
55
}
56
57
10664
Maybe<BaseObjectList> BaseObject::NestedTransferables() const {
58
10664
  return Just(BaseObjectList {});
59
}
60
61
10408
Maybe<bool> BaseObject::FinalizeTransferRead(
62
    Local<Context> context, ValueDeserializer* deserializer) {
63
10408
  return Just(true);
64
}
65
66
namespace worker {
67
68
10671
Maybe<bool> TransferData::FinalizeTransferWrite(
69
    Local<Context> context, ValueSerializer* serializer) {
70
10671
  return Just(true);
71
}
72
73
79102
Message::Message(MallocedBuffer<char>&& buffer)
74
79102
    : main_message_buf_(std::move(buffer)) {}
75
76
109498
bool Message::IsCloseMessage() const {
77
109498
  return main_message_buf_.data == nullptr;
78
}
79
80
namespace {
81
82
// This is used to tell V8 how to read transferred host objects, like other
83
// `MessagePort`s and `SharedArrayBuffer`s, and make new JS objects out of them.
84
43776
class DeserializerDelegate : public ValueDeserializer::Delegate {
85
 public:
86
44025
  DeserializerDelegate(
87
      Message* m,
88
      Environment* env,
89
      const std::vector<BaseObjectPtr<BaseObject>>& host_objects,
90
      const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers,
91
      const std::vector<CompiledWasmModule>& wasm_modules)
92
44025
      : host_objects_(host_objects),
93
        shared_array_buffers_(shared_array_buffers),
94
44025
        wasm_modules_(wasm_modules) {}
95
96
10413
  MaybeLocal<Object> ReadHostObject(Isolate* isolate) override {
97
    // Identifying the index in the message's BaseObject array is sufficient.
98
    uint32_t id;
99
10413
    if (!deserializer->ReadUint32(&id))
100
      return MaybeLocal<Object>();
101
10413
    CHECK_LE(id, host_objects_.size());
102
20826
    return host_objects_[id]->object(isolate);
103
  }
104
105
416
  MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
106
      Isolate* isolate, uint32_t clone_id) override {
107
416
    CHECK_LE(clone_id, shared_array_buffers_.size());
108
832
    return shared_array_buffers_[clone_id];
109
  }
110
111
2
  MaybeLocal<WasmModuleObject> GetWasmModuleFromId(
112
      Isolate* isolate, uint32_t transfer_id) override {
113
2
    CHECK_LE(transfer_id, wasm_modules_.size());
114
    return WasmModuleObject::FromCompiledModule(
115
2
        isolate, wasm_modules_[transfer_id]);
116
  }
117
118
  ValueDeserializer* deserializer = nullptr;
119
120
 private:
121
  const std::vector<BaseObjectPtr<BaseObject>>& host_objects_;
122
  const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers_;
123
  const std::vector<CompiledWasmModule>& wasm_modules_;
124
};
125
126
}  // anonymous namespace
127
128
44096
MaybeLocal<Value> Message::Deserialize(Environment* env,
129
                                       Local<Context> context) {
130
44096
  CHECK(!IsCloseMessage());
131
132
44104
  EscapableHandleScope handle_scope(env->isolate());
133
  Context::Scope context_scope(context);
134
135
  // Create all necessary objects for transferables, e.g. MessagePort handles.
136
88162
  std::vector<BaseObjectPtr<BaseObject>> host_objects(transferables_.size());
137
43690
  auto cleanup = OnScopeLeave([&]() {
138
43690
    for (BaseObjectPtr<BaseObject> object : host_objects) {
139
9
      if (!object) continue;
140
141
      // If the function did not finish successfully, host_objects will contain
142
      // a list of objects that will never be passed to JS. Therefore, we
143
      // destroy them here.
144
      object->Detach();
145
    }
146
132239
  });
147
148
54511
  for (uint32_t i = 0; i < transferables_.size(); ++i) {
149
10419
    TransferData* data = transferables_[i].get();
150
20838
    host_objects[i] = data->Deserialize(
151
20838
        env, context, std::move(transferables_[i]));
152
10425
    if (!host_objects[i]) return {};
153
  }
154
44056
  transferables_.clear();
155
156
87996
  std::vector<Local<SharedArrayBuffer>> shared_array_buffers;
157
  // Attach all transferred SharedArrayBuffers to their new Isolate.
158
44502
  for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) {
159
    Local<SharedArrayBuffer> sab =
160
416
        SharedArrayBuffer::New(env->isolate(), shared_array_buffers_[i]);
161
416
    shared_array_buffers.push_back(sab);
162
  }
163
164
  DeserializerDelegate delegate(
165
88132
      this, env, host_objects, shared_array_buffers, wasm_modules_);
166
  ValueDeserializer deserializer(
167
      env->isolate(),
168
44031
      reinterpret_cast<const uint8_t*>(main_message_buf_.data),
169
      main_message_buf_.size,
170
132119
      &delegate);
171
44101
  delegate.deserializer = &deserializer;
172
173
  // Attach all transferred ArrayBuffers to their new Isolate.
174
44110
  for (uint32_t i = 0; i < array_buffers_.size(); ++i) {
175
    Local<ArrayBuffer> ab =
176
9
        ArrayBuffer::New(env->isolate(), std::move(array_buffers_[i]));
177
9
    deserializer.TransferArrayBuffer(i, ab);
178
  }
179
180
88095
  if (deserializer.ReadHeader(context).IsNothing())
181
    return {};
182
  Local<Value> return_value;
183
88029
  if (!deserializer.ReadValue(context).ToLocal(&return_value))
184
    return {};
185
186
54448
  for (BaseObjectPtr<BaseObject> base_object : host_objects) {
187
20826
    if (base_object->FinalizeTransferRead(context, &deserializer).IsNothing())
188
      return {};
189
  }
190
191
44068
  host_objects.clear();
192
44057
  return handle_scope.Escape(return_value);
193
}
194
195
665
void Message::AddSharedArrayBuffer(
196
    std::shared_ptr<BackingStore> backing_store) {
197
665
  shared_array_buffers_.emplace_back(std::move(backing_store));
198
665
}
199
200
10680
void Message::AddTransferable(std::unique_ptr<TransferData>&& data) {
201
10680
  transferables_.emplace_back(std::move(data));
202
10680
}
203
204
2
uint32_t Message::AddWASMModule(CompiledWasmModule&& mod) {
205
2
  wasm_modules_.emplace_back(std::move(mod));
206
2
  return wasm_modules_.size() - 1;
207
}
208
209
namespace {
210
211
32892
MaybeLocal<Function> GetEmitMessageFunction(Local<Context> context) {
212
32892
  Isolate* isolate = context->GetIsolate();
213
  Local<Object> per_context_bindings;
214
  Local<Value> emit_message_val;
215

131568
  if (!GetPerContextExports(context).ToLocal(&per_context_bindings) ||
216
98676
      !per_context_bindings->Get(context,
217
98676
                                FIXED_ONE_BYTE_STRING(isolate, "emitMessage"))
218
32892
          .ToLocal(&emit_message_val)) {
219
    return MaybeLocal<Function>();
220
  }
221
32892
  CHECK(emit_message_val->IsFunction());
222
32892
  return emit_message_val.As<Function>();
223
}
224
225
460
MaybeLocal<Function> GetDOMException(Local<Context> context) {
226
460
  Isolate* isolate = context->GetIsolate();
227
  Local<Object> per_context_bindings;
228
  Local<Value> domexception_ctor_val;
229

1840
  if (!GetPerContextExports(context).ToLocal(&per_context_bindings) ||
230
1380
      !per_context_bindings->Get(context,
231
1380
                                FIXED_ONE_BYTE_STRING(isolate, "DOMException"))
232
460
          .ToLocal(&domexception_ctor_val)) {
233
    return MaybeLocal<Function>();
234
  }
235
460
  CHECK(domexception_ctor_val->IsFunction());
236
460
  Local<Function> domexception_ctor = domexception_ctor_val.As<Function>();
237
460
  return domexception_ctor;
238
}
239
240
16
void ThrowDataCloneException(Local<Context> context, Local<String> message) {
241
16
  Isolate* isolate = context->GetIsolate();
242
  Local<Value> argv[] = {message,
243
48
                         FIXED_ONE_BYTE_STRING(isolate, "DataCloneError")};
244
  Local<Value> exception;
245
  Local<Function> domexception_ctor;
246

64
  if (!GetDOMException(context).ToLocal(&domexception_ctor) ||
247
64
      !domexception_ctor->NewInstance(context, arraysize(argv), argv)
248
16
           .ToLocal(&exception)) {
249
    return;
250
  }
251
16
  isolate->ThrowException(exception);
252
}
253
254
// This tells V8 how to serialize objects that it does not understand
255
// (e.g. C++ objects) into the output buffer, in a way that our own
256
// DeserializerDelegate understands how to unpack.
257
45069
class SerializerDelegate : public ValueSerializer::Delegate {
258
 public:
259
45069
  SerializerDelegate(Environment* env, Local<Context> context, Message* m)
260
45069
      : env_(env), context_(context), msg_(m) {}
261
262
6
  void ThrowDataCloneError(Local<String> message) override {
263
6
    ThrowDataCloneException(context_, message);
264
6
  }
265
266
10687
  Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override {
267
21374
    if (env_->base_object_ctor_template()->HasInstance(object)) {
268
      return WriteHostObject(
269
10687
          BaseObjectPtr<BaseObject> { Unwrap<BaseObject>(object) });
270
    }
271
272
    ThrowDataCloneError(env_->clone_unsupported_type_str());
273
    return Nothing<bool>();
274
  }
275
276
665
  Maybe<uint32_t> GetSharedArrayBufferId(
277
      Isolate* isolate,
278
      Local<SharedArrayBuffer> shared_array_buffer) override {
279
    uint32_t i;
280
690
    for (i = 0; i < seen_shared_array_buffers_.size(); ++i) {
281
50
      if (PersistentToLocal::Strong(seen_shared_array_buffers_[i]) ==
282
          shared_array_buffer) {
283
        return Just(i);
284
      }
285
    }
286
287
665
    seen_shared_array_buffers_.emplace_back(
288
1330
      Global<SharedArrayBuffer> { isolate, shared_array_buffer });
289
665
    msg_->AddSharedArrayBuffer(shared_array_buffer->GetBackingStore());
290
665
    return Just(i);
291
  }
292
293
2
  Maybe<uint32_t> GetWasmModuleTransferId(
294
      Isolate* isolate, Local<WasmModuleObject> module) override {
295
2
    return Just(msg_->AddWASMModule(module->GetCompiledModule()));
296
  }
297
298
45050
  Maybe<bool> Finish(Local<Context> context) {
299
55730
    for (uint32_t i = 0; i < host_objects_.size(); i++) {
300
21364
      BaseObjectPtr<BaseObject> host_object = std::move(host_objects_[i]);
301
21364
      std::unique_ptr<TransferData> data;
302
10684
      if (i < first_cloned_object_index_)
303
10668
        data = host_object->TransferForMessaging();
304
10684
      if (!data)
305
19
        data = host_object->CloneForMessaging();
306
10684
      if (!data) return Nothing<bool>();
307
21362
      if (data->FinalizeTransferWrite(context, serializer).IsNothing())
308
1
        return Nothing<bool>();
309
10680
      msg_->AddTransferable(std::move(data));
310
    }
311
45046
    return Just(true);
312
  }
313
314
10675
  inline void AddHostObject(BaseObjectPtr<BaseObject> host_object) {
315
    // Make sure we have not started serializing the value itself yet.
316
10675
    CHECK_EQ(first_cloned_object_index_, SIZE_MAX);
317
10675
    host_objects_.emplace_back(std::move(host_object));
318
10675
  }
319
320
  // Some objects in the transfer list may register sub-objects that can be
321
  // transferred. This could e.g. be a public JS wrapper object, such as a
322
  // FileHandle, that is registering its C++ handle for transfer.
323
45059
  inline Maybe<bool> AddNestedHostObjects() {
324
55733
    for (size_t i = 0; i < host_objects_.size(); i++) {
325
21348
      std::vector<BaseObjectPtr<BaseObject>> nested_transferables;
326
21348
      if (!host_objects_[i]->NestedTransferables().To(&nested_transferables))
327
        return Nothing<bool>();
328

10684
      for (auto nested_transferable : nested_transferables) {
329
20
        if (std::find(host_objects_.begin(),
330
                      host_objects_.end(),
331
20
                      nested_transferable) == host_objects_.end()) {
332
10
          AddHostObject(nested_transferable);
333
        }
334
      }
335
    }
336
45059
    return Just(true);
337
  }
338
339
  ValueSerializer* serializer = nullptr;
340
341
 private:
342
10687
  Maybe<bool> WriteHostObject(BaseObjectPtr<BaseObject> host_object) {
343
10687
    BaseObject::TransferMode mode = host_object->GetTransferMode();
344
10687
    if (mode == BaseObject::TransferMode::kUntransferable) {
345
2
      ThrowDataCloneError(env_->clone_unsupported_type_str());
346
2
      return Nothing<bool>();
347
    }
348
349
10701
    for (uint32_t i = 0; i < host_objects_.size(); i++) {
350
10681
      if (host_objects_[i] == host_object) {
351
10665
        serializer->WriteUint32(i);
352
10665
        return Just(true);
353
      }
354
    }
355
356
20
    if (mode == BaseObject::TransferMode::kTransferable) {
357
4
      THROW_ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST(env_);
358
4
      return Nothing<bool>();
359
    }
360
361
16
    CHECK_EQ(mode, BaseObject::TransferMode::kCloneable);
362
16
    uint32_t index = host_objects_.size();
363
16
    if (first_cloned_object_index_ == SIZE_MAX)
364
13
      first_cloned_object_index_ = index;
365
16
    serializer->WriteUint32(index);
366
16
    host_objects_.push_back(host_object);
367
16
    return Just(true);
368
  }
369
370
  Environment* env_;
371
  Local<Context> context_;
372
  Message* msg_;
373
  std::vector<Global<SharedArrayBuffer>> seen_shared_array_buffers_;
374
  std::vector<BaseObjectPtr<BaseObject>> host_objects_;
375
  size_t first_cloned_object_index_ = SIZE_MAX;
376
377
  friend class worker::Message;
378
};
379
380
}  // anonymous namespace
381
382
45069
Maybe<bool> Message::Serialize(Environment* env,
383
                               Local<Context> context,
384
                               Local<Value> input,
385
                               const TransferList& transfer_list_v,
386
                               Local<Object> source_port) {
387
90137
  HandleScope handle_scope(env->isolate());
388
  Context::Scope context_scope(context);
389
390
  // Verify that we're not silently overwriting an existing message.
391
45069
  CHECK(main_message_buf_.is_empty());
392
393
90138
  SerializerDelegate delegate(env, context, this);
394
90138
  ValueSerializer serializer(env->isolate(), &delegate);
395
45069
  delegate.serializer = &serializer;
396
397
90138
  std::vector<Local<ArrayBuffer>> array_buffers;
398
55759
  for (uint32_t i = 0; i < transfer_list_v.length(); ++i) {
399
10700
    Local<Value> entry = transfer_list_v[i];
400
10700
    if (entry->IsObject()) {
401
      // See https://github.com/nodejs/node/pull/30339#issuecomment-552225353
402
      // for details.
403
      bool untransferable;
404
32100
      if (!entry.As<Object>()->HasPrivate(
405
              context,
406
21400
              env->untransferable_object_private_symbol())
407
10700
              .To(&untransferable)) {
408
        return Nothing<bool>();
409
      }
410
10700
      if (untransferable) continue;
411
    }
412
413
    // Currently, we support ArrayBuffers and BaseObjects for which
414
    // GetTransferMode() does not return kUntransferable.
415
10695
    if (entry->IsArrayBuffer()) {
416
21
      Local<ArrayBuffer> ab = entry.As<ArrayBuffer>();
417
      // If we cannot render the ArrayBuffer unusable in this Isolate,
418
      // copying the buffer will have to do.
419
      // Note that we can currently transfer ArrayBuffers even if they were
420
      // not allocated by Node’s ArrayBufferAllocator in the first place,
421
      // because we pass the underlying v8::BackingStore around rather than
422
      // raw data *and* an Isolate with a non-default ArrayBuffer allocator
423
      // is always going to outlive any Workers it creates, and so will its
424
      // allocator along with it.
425
41
      if (!ab->IsDetachable()) continue;
426
42
      if (std::find(array_buffers.begin(), array_buffers.end(), ab) !=
427
42
          array_buffers.end()) {
428
1
        ThrowDataCloneException(
429
            context,
430
            FIXED_ONE_BYTE_STRING(
431
                env->isolate(),
432
1
                "Transfer list contains duplicate ArrayBuffer"));
433
1
        return Nothing<bool>();
434
      }
435
      // We simply use the array index in the `array_buffers` list as the
436
      // ID that we write into the serialized buffer.
437
20
      uint32_t id = array_buffers.size();
438
20
      array_buffers.push_back(ab);
439
20
      serializer.TransferArrayBuffer(id, ab);
440
20
      continue;
441
21348
    } else if (env->base_object_ctor_template()->HasInstance(entry)) {
442
      // Check if the source MessagePort is being transferred.
443

21348
      if (!source_port.IsEmpty() && entry == source_port) {
444
1
        ThrowDataCloneException(
445
            context,
446
            FIXED_ONE_BYTE_STRING(env->isolate(),
447
1
                                  "Transfer list contains source port"));
448
10
        return Nothing<bool>();
449
      }
450
      BaseObjectPtr<BaseObject> host_object {
451
10673
          Unwrap<BaseObject>(entry.As<Object>()) };
452

32016
      if (env->message_port_constructor_template()->HasInstance(entry) &&
453
21325
          (!host_object ||
454
10662
           static_cast<MessagePort*>(host_object.get())->IsDetached())) {
455
7
        ThrowDataCloneException(
456
            context,
457
            FIXED_ONE_BYTE_STRING(
458
                env->isolate(),
459
7
                "MessagePort in transfer list is already detached"));
460
7
        return Nothing<bool>();
461
      }
462
21332
      if (std::find(delegate.host_objects_.begin(),
463
                    delegate.host_objects_.end(),
464
21332
                    host_object) != delegate.host_objects_.end()) {
465
1
        ThrowDataCloneException(
466
            context,
467
            String::Concat(env->isolate(),
468
                FIXED_ONE_BYTE_STRING(
469
                  env->isolate(),
470
                  "Transfer list contains duplicate "),
471
2
                entry.As<Object>()->GetConstructorName()));
472
1
        return Nothing<bool>();
473
      }
474

10665
      if (host_object && host_object->GetTransferMode() !=
475
10665
              BaseObject::TransferMode::kUntransferable) {
476
10665
        delegate.AddHostObject(host_object);
477
10665
        continue;
478
      }
479
    }
480
481
    THROW_ERR_INVALID_TRANSFER_OBJECT(env);
482
    return Nothing<bool>();
483
  }
484
90118
  if (delegate.AddNestedHostObjects().IsNothing())
485
    return Nothing<bool>();
486
487
45059
  serializer.WriteHeader();
488
90117
  if (serializer.WriteValue(context, input).IsNothing()) {
489
9
    return Nothing<bool>();
490
  }
491
492
45062
  for (Local<ArrayBuffer> ab : array_buffers) {
493
    // If serialization succeeded, we render it inaccessible in this Isolate.
494
24
    std::shared_ptr<BackingStore> backing_store = ab->GetBackingStore();
495
12
    ab->Detach();
496
497
12
    array_buffers_.emplace_back(std::move(backing_store));
498
  }
499
500
90100
  if (delegate.Finish(context).IsNothing())
501
4
    return Nothing<bool>();
502
503
  // The serializer gave us a buffer allocated using `malloc()`.
504
45046
  std::pair<uint8_t*, size_t> data = serializer.Release();
505
45046
  CHECK_NOT_NULL(data.first);
506
  main_message_buf_ =
507
45046
      MallocedBuffer<char>(reinterpret_cast<char*>(data.first), data.second);
508
45046
  return Just(true);
509
}
510
511
void Message::MemoryInfo(MemoryTracker* tracker) const {
512
  tracker->TrackField("array_buffers_", array_buffers_);
513
  tracker->TrackField("shared_array_buffers", shared_array_buffers_);
514
  tracker->TrackField("transferables", transferables_);
515
}
516
517
33528
MessagePortData::MessagePortData(MessagePort* owner)
518
33528
    : owner_(owner) {
519
33528
}
520
521
100316
MessagePortData::~MessagePortData() {
522
33439
  CHECK_NULL(owner_);
523
33439
  Disentangle();
524
66887
}
525
526
2
void MessagePortData::MemoryInfo(MemoryTracker* tracker) const {
527
4
  Mutex::ScopedLock lock(mutex_);
528
2
  tracker->TrackField("incoming_messages", incoming_messages_);
529
2
}
530
531
79004
void MessagePortData::AddToIncomingQueue(std::shared_ptr<Message> message) {
532
  // This function will be called by other threads.
533
158012
  Mutex::ScopedLock lock(mutex_);
534
79013
  incoming_messages_.emplace_back(std::move(message));
535
536
79005
  if (owner_ != nullptr) {
537
54506
    Debug(owner_, "Adding message to incoming queue");
538
54505
    owner_->TriggerAsync();
539
  }
540
79012
}
541
542
11349
void MessagePortData::Entangle(MessagePortData* a, MessagePortData* b) {
543
22698
  auto group = std::make_shared<SiblingGroup>();
544
11349
  group->Entangle({a, b});
545
11349
}
546
547
55624
void MessagePortData::Disentangle() {
548
55624
  if (group_) {
549
22692
    group_->Disentangle(this);
550
  }
551
55624
}
552
553
131370
MessagePort::~MessagePort() {
554
32841
  if (data_) Detach();
555
65689
}
556
557
32892
MessagePort::MessagePort(Environment* env,
558
                         Local<Context> context,
559
32892
                         Local<Object> wrap)
560
  : HandleWrap(env,
561
               wrap,
562
32892
               reinterpret_cast<uv_handle_t*>(&async_),
563
               AsyncWrap::PROVIDER_MESSAGEPORT),
564
32892
    data_(new MessagePortData(this)) {
565
96690
  auto onmessage = [](uv_async_t* handle) {
566
    // Called when data has been put into the queue.
567
31899
    MessagePort* channel = ContainerOf(&MessagePort::async_, handle);
568
31899
    channel->OnMessage();
569
96681
  };
570
571
32892
  CHECK_EQ(uv_async_init(env->event_loop(),
572
                         &async_,
573
                         onmessage), 0);
574
  // Reset later to indicate success of the constructor.
575
32892
  bool succeeded = false;
576
98676
  auto cleanup = OnScopeLeave([&]() { if (!succeeded) Close(); });
577
578
  Local<Value> fn;
579
98676
  if (!wrap->Get(context, env->oninit_symbol()).ToLocal(&fn))
580
    return;
581
582
32892
  if (fn->IsFunction()) {
583
32887
    Local<Function> init = fn.As<Function>();
584
65774
    if (init->Call(context, wrap, 0, nullptr).IsEmpty())
585
      return;
586
  }
587
588
  Local<Function> emit_message_fn;
589
65784
  if (!GetEmitMessageFunction(context).ToLocal(&emit_message_fn))
590
    return;
591
32892
  emit_message_fn_.Reset(env->isolate(), emit_message_fn);
592
593
32892
  succeeded = true;
594
32892
  Debug(this, "Created message port");
595
}
596
597
31977
bool MessagePort::IsDetached() const {
598

31977
  return data_ == nullptr || IsHandleClosing();
599
}
600
601
76191
void MessagePort::TriggerAsync() {
602
76191
  if (IsHandleClosing()) return;
603
76154
  CHECK_EQ(uv_async_send(&async_), 0);
604
}
605
606
32845
void MessagePort::Close(v8::Local<v8::Value> close_callback) {
607
65691
  Debug(this, "Closing message port, data set = %d", static_cast<int>(!!data_));
608
609
32846
  if (data_) {
610
    // Wrap this call with accessing the mutex, so that TriggerAsync()
611
    // can check IsHandleClosing() without race conditions.
612
65683
    Mutex::ScopedLock sibling_lock(data_->mutex_);
613
32843
    HandleWrap::Close(close_callback);
614
  } else {
615
5
    HandleWrap::Close(close_callback);
616
  }
617
32848
}
618
619
2
void MessagePort::New(const FunctionCallbackInfo<Value>& args) {
620
  // This constructor just throws an error. Unfortunately, we can’t use V8’s
621
  // ConstructorBehavior::kThrow, as that also removes the prototype from the
622
  // class (i.e. makes it behave like an arrow function).
623
2
  Environment* env = Environment::GetCurrent(args);
624
2
  THROW_ERR_CONSTRUCT_CALL_INVALID(env);
625
2
}
626
627
32892
MessagePort* MessagePort::New(
628
    Environment* env,
629
    Local<Context> context,
630
    std::unique_ptr<MessagePortData> data,
631
    std::shared_ptr<SiblingGroup> sibling_group) {
632
  Context::Scope context_scope(context);
633
32892
  Local<FunctionTemplate> ctor_templ = GetMessagePortConstructorTemplate(env);
634
635
  // Construct a new instance, then assign the listener instance and possibly
636
  // the MessagePortData to it.
637
  Local<Object> instance;
638
98676
  if (!ctor_templ->InstanceTemplate()->NewInstance(context).ToLocal(&instance))
639
    return nullptr;
640
32892
  MessagePort* port = new MessagePort(env, context, instance);
641
32892
  CHECK_NOT_NULL(port);
642
32892
  if (port->IsHandleClosing()) {
643
    // Construction failed with an exception.
644
    return nullptr;
645
  }
646
647
32892
  if (data) {
648
10791
    CHECK(!sibling_group);
649
10791
    port->Detach();
650
10791
    port->data_ = std::move(data);
651
652
    // This lock is here to avoid race conditions with the `owner_` read
653
    // in AddToIncomingQueue(). (This would likely be unproblematic without it,
654
    // but it's better to be safe than sorry.)
655
21582
    Mutex::ScopedLock lock(port->data_->mutex_);
656
10791
    port->data_->owner_ = port;
657
    // If the existing MessagePortData object had pending messages, this is
658
    // the easiest way to run that queue.
659
10791
    port->TriggerAsync();
660
22101
  } else if (sibling_group) {
661
39
    sibling_group->Entangle(port->data_.get());
662
  }
663
32892
  return port;
664
}
665
666
76386
MaybeLocal<Value> MessagePort::ReceiveMessage(Local<Context> context,
667
                                              bool only_if_receiving) {
668
152782
  std::shared_ptr<Message> received;
669
  {
670
    // Get the head of the message queue.
671
131743
    Mutex::ScopedLock lock(data_->mutex_);
672
673
76433
    Debug(this, "MessagePort has message");
674
675

76434
    bool wants_message = receiving_messages_ || !only_if_receiving;
676
    // We have nothing to do if:
677
    // - There are no pending messages
678
    // - We are not intending to receive messages, and the message we would
679
    //   receive is not the final "close" message.
680

152844
    if (data_->incoming_messages_.empty() ||
681
65603
        (!wants_message &&
682
10269
         !data_->incoming_messages_.front()->IsCloseMessage())) {
683
42154
      return env()->no_message_symbol();
684
    }
685
686
55315
    received = data_->incoming_messages_.front();
687
55364
    data_->incoming_messages_.pop_front();
688
  }
689
690
55357
  if (received->IsCloseMessage()) {
691
22506
    Close();
692
22506
    return env()->no_message_symbol();
693
  }
694
695
44108
  if (!env()->can_call_into_js()) return MaybeLocal<Value>();
696
697
44108
  return received->Deserialize(env(), context);
698
}
699
700
32393
void MessagePort::OnMessage() {
701
32393
  Debug(this, "Running MessagePort::OnMessage()");
702
64721
  HandleScope handle_scope(env()->isolate());
703
64786
  Local<Context> context = object(env()->isolate())->CreationContext();
704
705
  size_t processing_limit;
706
  {
707
32393
    Mutex::ScopedLock(data_->mutex_);
708
64786
    processing_limit = std::max(data_->incoming_messages_.size(),
709
97179
                                static_cast<size_t>(1000));
710
  }
711
712
  // data_ can only ever be modified by the owner thread, so no need to lock.
713
  // However, the message port may be transferred while it is processing
714
  // messages, so we need to check that this handle still owns its `data_` field
715
  // on every iteration.
716

120483
  while (data_) {
717
76366
    if (processing_limit-- == 0) {
718
      // Prevent event loop starvation by only processing those messages without
719
      // interruption that were already present when the OnMessage() call was
720
      // first triggered, but at least 1000 messages because otherwise the
721
      // overhead of repeatedly triggering the uv_async_t instance becomes
722
      // noticable, at least on Windows.
723
      // (That might require more investigation by somebody more familiar with
724
      // Windows.)
725
1
      TriggerAsync();
726
1
      return;
727
    }
728
729
120410
    HandleScope handle_scope(env()->isolate());
730

44045
    Context::Scope context_scope(context);
731
76378
    Local<Function> emit_message = PersistentToLocal::Strong(emit_message_fn_);
732
733
    Local<Value> payload;
734
    Local<Value> message_error;
735
229121
    Local<Value> argv[2];
736
737
    {
738
      // Catch any exceptions from parsing the message itself (not from
739
      // emitting it) as 'messageeror' events.
740
152430
      TryCatchScope try_catch(env());
741
152338
      if (!ReceiveMessage(context, true).ToLocal(&payload)) {
742

6
        if (try_catch.HasCaught() && !try_catch.HasTerminated())
743
6
          message_error = try_catch.Exception();
744
6
        goto reschedule;
745
      }
746
    }
747
152473
    if (payload == env()->no_message_symbol()) break;
748
749
44092
    if (!env()->can_call_into_js()) {
750
      Debug(this, "MessagePort drains queue because !can_call_into_js()");
751
      // In this case there is nothing to do but to drain the current queue.
752
      continue;
753
    }
754
755
44071
    argv[0] = payload;
756
88118
    argv[1] = env()->message_string();
757
758
88145
    if (MakeCallback(emit_message, arraysize(argv), argv).IsEmpty()) {
759
    reschedule:
760
61
      if (!message_error.IsEmpty()) {
761
6
        argv[0] = message_error;
762
12
        argv[1] = env()->messageerror_string();
763
6
        USE(MakeCallback(emit_message, arraysize(argv), argv));
764
      }
765
766
      // Re-schedule OnMessage() execution in case of failure.
767
61
      if (data_)
768
61
        TriggerAsync();
769
61
      return;
770
    }
771
  }
772
}
773
774
32844
void MessagePort::OnClose() {
775
32844
  Debug(this, "MessagePort::OnClose()");
776
32844
  if (data_) {
777
    // Detach() returns move(data_).
778
22190
    Detach()->Disentangle();
779
  }
780
32844
}
781
782
43617
std::unique_ptr<MessagePortData> MessagePort::Detach() {
783
43617
  CHECK(data_);
784
87247
  Mutex::ScopedLock lock(data_->mutex_);
785
43632
  data_->owner_ = nullptr;
786
87269
  return std::move(data_);
787
}
788
789
21310
BaseObject::TransferMode MessagePort::GetTransferMode() const {
790
21310
  if (IsDetached())
791
1
    return BaseObject::TransferMode::kUntransferable;
792
21309
  return BaseObject::TransferMode::kTransferable;
793
}
794
795
10652
std::unique_ptr<TransferData> MessagePort::TransferForMessaging() {
796
21304
  Close();
797
10652
  return Detach();
798
}
799
800
10396
BaseObjectPtr<BaseObject> MessagePortData::Deserialize(
801
    Environment* env,
802
    Local<Context> context,
803
    std::unique_ptr<TransferData> self) {
804
41584
  return BaseObjectPtr<MessagePort> { MessagePort::New(
805
      env, context,
806
41584
      static_unique_pointer_cast<MessagePortData>(std::move(self))) };
807
}
808
809
45068
Maybe<bool> MessagePort::PostMessage(Environment* env,
810
                                     Local<Value> message_v,
811
                                     const TransferList& transfer_v) {
812
45068
  Isolate* isolate = env->isolate();
813
45068
  Local<Object> obj = object(isolate);
814
45068
  Local<Context> context = obj->CreationContext();
815
816
90136
  std::shared_ptr<Message> msg = std::make_shared<Message>();
817
818
  // Per spec, we need to both check if transfer list has the source port, and
819
  // serialize the input message, even if the MessagePort is closed or detached.
820
821
  Maybe<bool> serialization_maybe =
822
45068
      msg->Serialize(env, context, message_v, transfer_v, obj);
823
45067
  if (data_ == nullptr) {
824
2
    return serialization_maybe;
825
  }
826
45066
  if (serialization_maybe.IsNothing()) {
827
20
    return Nothing<bool>();
828
  }
829
830
90092
  std::string error;
831
45046
  Maybe<bool> res = data_->Dispatch(msg, &error);
832
45046
  if (res.IsNothing())
833
    return res;
834
835
45046
  if (!error.empty())
836
2
    ProcessEmitWarning(env, error.c_str());
837
838
45046
  return res;
839
}
840
841
45046
Maybe<bool> MessagePortData::Dispatch(
842
    std::shared_ptr<Message> message,
843
    std::string* error) {
844
45046
  if (!group_) {
845
    if (error != nullptr)
846
      *error = "MessagePortData is not entangled.";
847
    return Nothing<bool>();
848
  }
849
45046
  return group_->Dispatch(this, message, error);
850
}
851
852
10708
static Maybe<bool> ReadIterable(Environment* env,
853
                                Local<Context> context,
854
                                // NOLINTNEXTLINE(runtime/references)
855
                                TransferList& transfer_list,
856
                                Local<Value> object) {
857
10708
  if (!object->IsObject()) return Just(false);
858
859
10705
  if (object->IsArray()) {
860
10685
    Local<Array> arr = object.As<Array>();
861
10685
    size_t length = arr->Length();
862
10685
    transfer_list.AllocateSufficientStorage(length);
863
21383
    for (size_t i = 0; i < length; i++) {
864
32094
      if (!arr->Get(context, i).ToLocal(&transfer_list[i]))
865
        return Nothing<bool>();
866
    }
867
10685
    return Just(true);
868
  }
869
870
20
  Isolate* isolate = env->isolate();
871
  Local<Value> iterator_method;
872
80
  if (!object.As<Object>()->Get(context, Symbol::GetIterator(isolate))
873
20
      .ToLocal(&iterator_method)) return Nothing<bool>();
874
20
  if (!iterator_method->IsFunction()) return Just(false);
875
876
  Local<Value> iterator;
877
18
  if (!iterator_method.As<Function>()->Call(context, object, 0, nullptr)
878
6
      .ToLocal(&iterator)) return Nothing<bool>();
879
6
  if (!iterator->IsObject()) return Just(false);
880
881
  Local<Value> next;
882
24
  if (!iterator.As<Object>()->Get(context, env->next_string()).ToLocal(&next))
883
    return Nothing<bool>();
884
6
  if (!next->IsFunction()) return Just(false);
885
886
6
  std::vector<Local<Value>> entries;
887
7
  while (env->can_call_into_js()) {
888
    Local<Value> result;
889
15
    if (!next.As<Function>()->Call(context, iterator, 0, nullptr)
890
7
        .ToLocal(&result)) return Nothing<bool>();
891
4
    if (!result->IsObject()) return Just(false);
892
893
    Local<Value> done;
894
16
    if (!result.As<Object>()->Get(context, env->done_string()).ToLocal(&done))
895
      return Nothing<bool>();
896
4
    if (done->BooleanValue(isolate)) break;
897
898
    Local<Value> val;
899
8
    if (!result.As<Object>()->Get(context, env->value_string()).ToLocal(&val))
900
      return Nothing<bool>();
901
2
    entries.push_back(val);
902
  }
903
904
2
  transfer_list.AllocateSufficientStorage(entries.size());
905
2
  std::copy(entries.begin(), entries.end(), &transfer_list[0]);
906
2
  return Just(true);
907
}
908
909
45081
void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) {
910
45081
  Environment* env = Environment::GetCurrent(args);
911
45081
  Local<Object> obj = args.This();
912
45081
  Local<Context> context = obj->CreationContext();
913
914
45081
  if (args.Length() == 0) {
915
    return THROW_ERR_MISSING_ARGS(env, "Not enough arguments to "
916
13
                                       "MessagePort.postMessage");
917
  }
918
919

156645
  if (!args[1]->IsNullOrUndefined() && !args[1]->IsObject()) {
920
    // Browsers ignore null or undefined, and otherwise accept an array or an
921
    // options object.
922
    return THROW_ERR_INVALID_ARG_TYPE(env,
923
4
        "Optional transferList argument must be an iterable");
924
  }
925
926
90145
  TransferList transfer_list;
927
90154
  if (args[1]->IsObject()) {
928
    bool was_iterable;
929
21394
    if (!ReadIterable(env, context, transfer_list, args[1]).To(&was_iterable))
930
8
      return;
931
10697
    if (!was_iterable) {
932
      Local<Value> transfer_option;
933
65
      if (!args[1].As<Object>()->Get(context, env->transfer_string())
934
21
          .ToLocal(&transfer_option)) return;
935
26
      if (!transfer_option->IsUndefined()) {
936
22
        if (!ReadIterable(env, context, transfer_list, transfer_option)
937
12
            .To(&was_iterable)) return;
938
10
        if (!was_iterable) {
939
          return THROW_ERR_INVALID_ARG_TYPE(env,
940
7
              "Optional options.transfer argument must be an iterable");
941
        }
942
      }
943
    }
944
  }
945
946
45069
  MessagePort* port = Unwrap<MessagePort>(args.This());
947
  // Even if the backing MessagePort object has already been deleted, we still
948
  // want to serialize the message to ensure spec-compliant behavior w.r.t.
949
  // transfers.
950
45069
  if (port == nullptr) {
951
2
    Message msg;
952
1
    USE(msg.Serialize(env, context, args[0], transfer_list, obj));
953
1
    return;
954
  }
955
956
45068
  Maybe<bool> res = port->PostMessage(env, args[0], transfer_list);
957
45068
  if (res.IsJust())
958
135138
    args.GetReturnValue().Set(res.FromJust());
959
}
960
961
23256
void MessagePort::Start() {
962
23256
  Debug(this, "Start receiving messages");
963
23256
  receiving_messages_ = true;
964
46512
  Mutex::ScopedLock lock(data_->mutex_);
965
23256
  if (!data_->incoming_messages_.empty())
966
10834
    TriggerAsync();
967
23256
}
968
969
20327
void MessagePort::Stop() {
970
20327
  Debug(this, "Stop receiving messages");
971
20327
  receiving_messages_ = false;
972
20327
}
973
974
23257
void MessagePort::Start(const FunctionCallbackInfo<Value>& args) {
975
  MessagePort* port;
976
23258
  ASSIGN_OR_RETURN_UNWRAP(&port, args.This());
977
23257
  if (!port->data_) {
978
1
    return;
979
  }
980
23256
  port->Start();
981
}
982
983
20518
void MessagePort::Stop(const FunctionCallbackInfo<Value>& args) {
984
  MessagePort* port;
985
41036
  CHECK(args[0]->IsObject());
986
41227
  ASSIGN_OR_RETURN_UNWRAP(&port, args[0].As<Object>());
987
20329
  if (!port->data_) {
988
2
    return;
989
  }
990
20327
  port->Stop();
991
}
992
993
6
void MessagePort::CheckType(const FunctionCallbackInfo<Value>& args) {
994
6
  Environment* env = Environment::GetCurrent(args);
995
18
  args.GetReturnValue().Set(
996
18
      GetMessagePortConstructorTemplate(env)->HasInstance(args[0]));
997
6
}
998
999
1214
void MessagePort::Drain(const FunctionCallbackInfo<Value>& args) {
1000
  MessagePort* port;
1001
2428
  ASSIGN_OR_RETURN_UNWRAP(&port, args[0].As<Object>());
1002
494
  port->OnMessage();
1003
}
1004
1005
11
void MessagePort::ReceiveMessage(const FunctionCallbackInfo<Value>& args) {
1006
11
  Environment* env = Environment::GetCurrent(args);
1007

41
  if (!args[0]->IsObject() ||
1008
27
      !env->message_port_constructor_template()->HasInstance(args[0])) {
1009
    return THROW_ERR_INVALID_ARG_TYPE(env,
1010
10
        "The \"port\" argument must be a MessagePort instance");
1011
  }
1012
12
  MessagePort* port = Unwrap<MessagePort>(args[0].As<Object>());
1013
6
  if (port == nullptr) {
1014
    // Return 'no messages' for a closed port.
1015
    args.GetReturnValue().Set(
1016
        Environment::GetCurrent(args)->no_message_symbol());
1017
    return;
1018
  }
1019
1020
  MaybeLocal<Value> payload =
1021
12
      port->ReceiveMessage(port->object()->CreationContext(), false);
1022
6
  if (!payload.IsEmpty())
1023
12
    args.GetReturnValue().Set(payload.ToLocalChecked());
1024
}
1025
1026
5
void MessagePort::MoveToContext(const FunctionCallbackInfo<Value>& args) {
1027
5
  Environment* env = Environment::GetCurrent(args);
1028

20
  if (!args[0]->IsObject() ||
1029
15
      !env->message_port_constructor_template()->HasInstance(args[0])) {
1030
    return THROW_ERR_INVALID_ARG_TYPE(env,
1031
        "The \"port\" argument must be a MessagePort instance");
1032
  }
1033
10
  MessagePort* port = Unwrap<MessagePort>(args[0].As<Object>());
1034
5
  CHECK_NOT_NULL(port);
1035
1036
5
  Local<Value> context_arg = args[1];
1037
  ContextifyContext* context_wrapper;
1038

15
  if (!context_arg->IsObject() ||
1039
      (context_wrapper = ContextifyContext::ContextFromContextifiedSandbox(
1040
10
          env, context_arg.As<Object>())) == nullptr) {
1041
    return THROW_ERR_INVALID_ARG_TYPE(env, "Invalid context argument");
1042
  }
1043
1044
10
  std::unique_ptr<MessagePortData> data;
1045
5
  if (!port->IsDetached())
1046
5
    data = port->Detach();
1047
1048
5
  Context::Scope context_scope(context_wrapper->context());
1049
  MessagePort* target =
1050
5
      MessagePort::New(env, context_wrapper->context(), std::move(data));
1051
5
  if (target != nullptr)
1052
15
    args.GetReturnValue().Set(target->object());
1053
}
1054
1055
10713
void MessagePort::Entangle(MessagePort* a, MessagePort* b) {
1056
10713
  MessagePortData::Entangle(a->data_.get(), b->data_.get());
1057
10713
}
1058
1059
636
void MessagePort::Entangle(MessagePort* a, MessagePortData* b) {
1060
636
  MessagePortData::Entangle(a->data_.get(), b);
1061
636
}
1062
1063
2
void MessagePort::MemoryInfo(MemoryTracker* tracker) const {
1064
2
  tracker->TrackField("data", data_);
1065
2
  tracker->TrackField("emit_message_fn", emit_message_fn_);
1066
2
}
1067
1068
33786
Local<FunctionTemplate> GetMessagePortConstructorTemplate(Environment* env) {
1069
  // Factor generating the MessagePort JS constructor into its own piece
1070
  // of code, because it is needed early on in the child environment setup.
1071
33786
  Local<FunctionTemplate> templ = env->message_port_constructor_template();
1072
33786
  if (!templ.IsEmpty())
1073
33342
    return templ;
1074
1075
  {
1076
444
    Local<FunctionTemplate> m = env->NewFunctionTemplate(MessagePort::New);
1077
888
    m->SetClassName(env->message_port_constructor_string());
1078
1332
    m->InstanceTemplate()->SetInternalFieldCount(
1079
444
        MessagePort::kInternalFieldCount);
1080
888
    m->Inherit(HandleWrap::GetConstructorTemplate(env));
1081
1082
444
    env->SetProtoMethod(m, "postMessage", MessagePort::PostMessage);
1083
444
    env->SetProtoMethod(m, "start", MessagePort::Start);
1084
1085
444
    env->set_message_port_constructor_template(m);
1086
  }
1087
1088
444
  return GetMessagePortConstructorTemplate(env);
1089
}
1090
1091
3331
JSTransferable::JSTransferable(Environment* env, Local<Object> obj)
1092
3331
    : BaseObject(env, obj) {
1093
3331
  MakeWeak();
1094
3331
}
1095
1096
3331
void JSTransferable::New(const FunctionCallbackInfo<Value>& args) {
1097
3331
  CHECK(args.IsConstructCall());
1098
6662
  new JSTransferable(Environment::GetCurrent(args), args.This());
1099
3331
}
1100
1101
24
JSTransferable::TransferMode JSTransferable::GetTransferMode() const {
1102
  // Implement `kClone in this ? kCloneable : kTransferable`.
1103
48
  HandleScope handle_scope(env()->isolate());
1104
48
  errors::TryCatchScope ignore_exceptions(env());
1105
1106
  bool has_clone;
1107
96
  if (!object()->Has(env()->context(),
1108
120
                     env()->messaging_clone_symbol()).To(&has_clone)) {
1109
    return TransferMode::kUntransferable;
1110
  }
1111
1112
24
  return has_clone ? TransferMode::kCloneable : TransferMode::kTransferable;
1113
}
1114
1115
10
std::unique_ptr<TransferData> JSTransferable::TransferForMessaging() {
1116
10
  return TransferOrClone(TransferMode::kTransferable);
1117
}
1118
1119
6
std::unique_ptr<TransferData> JSTransferable::CloneForMessaging() const {
1120
6
  return TransferOrClone(TransferMode::kCloneable);
1121
}
1122
1123
16
std::unique_ptr<TransferData> JSTransferable::TransferOrClone(
1124
    TransferMode mode) const {
1125
  // Call `this[symbol]()` where `symbol` is `kClone` or `kTransfer`,
1126
  // which should return an object with `data` and `deserializeInfo` properties;
1127
  // `data` is written to the serializer later, and `deserializeInfo` is stored
1128
  // on the `TransferData` instance as a string.
1129
32
  HandleScope handle_scope(env()->isolate());
1130
16
  Local<Context> context = env()->isolate()->GetCurrentContext();
1131
  Local<Symbol> method_name = mode == TransferMode::kCloneable ?
1132
16
      env()->messaging_clone_symbol() : env()->messaging_transfer_symbol();
1133
1134
  Local<Value> method;
1135
48
  if (!object()->Get(context, method_name).ToLocal(&method)) {
1136
    return {};
1137
  }
1138
16
  if (method->IsFunction()) {
1139
    Local<Value> result_v;
1140
52
    if (!method.As<Function>()->Call(
1141
52
            context, object(), 0, nullptr).ToLocal(&result_v)) {
1142
16
      return {};
1143
    }
1144
1145
10
    if (result_v->IsObject()) {
1146
10
      Local<Object> result = result_v.As<Object>();
1147
      Local<Value> data;
1148
      Local<Value> deserialize_info;
1149

50
      if (!result->Get(context, env()->data_string()).ToLocal(&data) ||
1150
40
          !result->Get(context, env()->deserialize_info_string())
1151
10
              .ToLocal(&deserialize_info)) {
1152
        return {};
1153
      }
1154
20
      Utf8Value deserialize_info_str(env()->isolate(), deserialize_info);
1155
10
      if (*deserialize_info_str == nullptr) return {};
1156
20
      return std::make_unique<Data>(
1157
50
          *deserialize_info_str, Global<Value>(env()->isolate(), data));
1158
    }
1159
  }
1160
1161
3
  if (mode == TransferMode::kTransferable)
1162
    return TransferOrClone(TransferMode::kCloneable);
1163
  else
1164
3
    return {};
1165
}
1166
1167
Maybe<BaseObjectList>
1168
10
JSTransferable::NestedTransferables() const {
1169
  // Call `this[kTransferList]()` and return the resulting list of BaseObjects.
1170
20
  HandleScope handle_scope(env()->isolate());
1171
10
  Local<Context> context = env()->isolate()->GetCurrentContext();
1172
10
  Local<Symbol> method_name = env()->messaging_transfer_list_symbol();
1173
1174
  Local<Value> method;
1175
30
  if (!object()->Get(context, method_name).ToLocal(&method)) {
1176
    return Nothing<BaseObjectList>();
1177
  }
1178
10
  if (!method->IsFunction()) return Just(BaseObjectList {});
1179
1180
  Local<Value> list_v;
1181
40
  if (!method.As<Function>()->Call(
1182
40
          context, object(), 0, nullptr).ToLocal(&list_v)) {
1183
    return Nothing<BaseObjectList>();
1184
  }
1185
10
  if (!list_v->IsArray()) return Just(BaseObjectList {});
1186
10
  Local<Array> list = list_v.As<Array>();
1187
1188
20
  BaseObjectList ret;
1189
40
  for (size_t i = 0; i < list->Length(); i++) {
1190
    Local<Value> value;
1191
30
    if (!list->Get(context, i).ToLocal(&value))
1192
      return Nothing<BaseObjectList>();
1193
20
    if (env()->base_object_ctor_template()->HasInstance(value))
1194
10
      ret.emplace_back(Unwrap<BaseObject>(value));
1195
  }
1196
10
  return Just(ret);
1197
}
1198
1199
5
Maybe<bool> JSTransferable::FinalizeTransferRead(
1200
    Local<Context> context, ValueDeserializer* deserializer) {
1201
  // Call `this[kDeserialize](data)` where `data` comes from the return value
1202
  // of `this[kTransfer]()` or `this[kClone]()`.
1203
10
  HandleScope handle_scope(env()->isolate());
1204
  Local<Value> data;
1205
10
  if (!deserializer->ReadValue(context).ToLocal(&data)) return Nothing<bool>();
1206
1207
5
  Local<Symbol> method_name = env()->messaging_deserialize_symbol();
1208
  Local<Value> method;
1209
15
  if (!object()->Get(context, method_name).ToLocal(&method)) {
1210
    return Nothing<bool>();
1211
  }
1212
5
  if (!method->IsFunction()) return Just(true);
1213
1214
20
  if (method.As<Function>()->Call(context, object(), 1, &data).IsEmpty()) {
1215
    return Nothing<bool>();
1216
  }
1217
5
  return Just(true);
1218
}
1219
1220
10
JSTransferable::Data::Data(std::string&& deserialize_info,
1221
10
                           v8::Global<v8::Value>&& data)
1222
10
    : deserialize_info_(std::move(deserialize_info)),
1223
30
      data_(std::move(data)) {}
1224
1225
8
BaseObjectPtr<BaseObject> JSTransferable::Data::Deserialize(
1226
    Environment* env,
1227
    Local<Context> context,
1228
    std::unique_ptr<TransferData> self) {
1229
  // Create the JS wrapper object that will later be filled with data passed to
1230
  // the `[kDeserialize]()` method on it. This split is necessary, because here
1231
  // we need to create an object with the right prototype and internal fields,
1232
  // but the actual JS data stored in the serialized data can only be read at
1233
  // the end of the stream, after the main message has been read.
1234
1235
16
  if (context != env->context()) {
1236
1
    THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env);
1237
1
    return {};
1238
  }
1239
14
  HandleScope handle_scope(env->isolate());
1240
  Local<Value> info;
1241
14
  if (!ToV8Value(context, deserialize_info_).ToLocal(&info)) return {};
1242
1243
  Local<Value> ret;
1244
14
  CHECK(!env->messaging_deserialize_create_object().IsEmpty());
1245
42
  if (!env->messaging_deserialize_create_object()->Call(
1246

40
          context, Null(env->isolate()), 1, &info).ToLocal(&ret) ||
1247
17
      !env->base_object_ctor_template()->HasInstance(ret)) {
1248
2
    return {};
1249
  }
1250
1251
5
  return BaseObjectPtr<BaseObject> { Unwrap<BaseObject>(ret) };
1252
}
1253
1254
10
Maybe<bool> JSTransferable::Data::FinalizeTransferWrite(
1255
    Local<Context> context, ValueSerializer* serializer) {
1256
20
  HandleScope handle_scope(context->GetIsolate());
1257
10
  auto ret = serializer->WriteValue(context, PersistentToLocal::Strong(data_));
1258
10
  data_.Reset();
1259
20
  return ret;
1260
}
1261
1262
39
std::shared_ptr<SiblingGroup> SiblingGroup::Get(const std::string& name) {
1263
78
  Mutex::ScopedLock lock(SiblingGroup::groups_mutex_);
1264
39
  std::shared_ptr<SiblingGroup> group;
1265
39
  auto i = groups_.find(name);
1266

39
  if (i == groups_.end() || i->second.expired()) {
1267
19
    group = std::make_shared<SiblingGroup>(name);
1268
19
    groups_[name] = group;
1269
  } else {
1270
20
    group = i->second.lock();
1271
  }
1272
78
  return group;
1273
}
1274
1275
19
void SiblingGroup::CheckSiblingGroup(const std::string& name) {
1276
38
  Mutex::ScopedLock lock(SiblingGroup::groups_mutex_);
1277
19
  auto i = groups_.find(name);
1278

19
  if (i != groups_.end() && i->second.expired())
1279
19
    groups_.erase(name);
1280
19
}
1281
1282
19
SiblingGroup::SiblingGroup(const std::string& name)
1283
19
    : name_(name) { }
1284
1285
22648
SiblingGroup::~SiblingGroup() {
1286
  // If this is a named group, check to see if we can remove the group
1287
11324
  if (!name_.empty())
1288
19
    CheckSiblingGroup(name_);
1289
11324
}
1290
1291
45046
Maybe<bool> SiblingGroup::Dispatch(
1292
    MessagePortData* source,
1293
    std::shared_ptr<Message> message,
1294
    std::string* error) {
1295
1296
90092
  Mutex::ScopedLock lock(group_mutex_);
1297
1298
  // The source MessagePortData is not part of this group.
1299
45046
  if (ports_.find(source) == ports_.end()) {
1300
    if (error != nullptr)
1301
      *error = "Source MessagePort is not entangled with this group.";
1302
    return Nothing<bool>();
1303
  }
1304
1305
  // There are no destination ports.
1306
45046
  if (size() <= 1)
1307
79
    return Just(false);
1308
1309
  // Transferables cannot be used when there is more
1310
  // than a single destination.
1311

44967
  if (size() > 2 && message->has_transferables()) {
1312
    if (error != nullptr)
1313
      *error = "Transferables cannot be used with multiple destinations.";
1314
    return Nothing<bool>();
1315
  }
1316
1317
134907
  for (MessagePortData* port : ports_) {
1318
89942
    if (port == source)
1319
44964
      continue;
1320
    // This loop should only be entered if there's only a single destination
1321
55655
    for (const auto& transferable : message->transferables()) {
1322
10679
      if (port == transferable.get()) {
1323
2
        if (error != nullptr) {
1324
          *error = "The target port was posted to itself, and the "
1325
2
                   "communication channel was lost";
1326
        }
1327
2
        return Just(true);
1328
      }
1329
    }
1330
44976
    port->AddToIncomingQueue(message);
1331
  }
1332
1333
44965
  return Just(true);
1334
}
1335
1336
39
void SiblingGroup::Entangle(MessagePortData* port) {
1337
39
  Entangle({ port });
1338
39
}
1339
1340
11388
void SiblingGroup::Entangle(std::initializer_list<MessagePortData*> ports) {
1341
22776
  Mutex::ScopedLock lock(group_mutex_);
1342
34125
  for (MessagePortData* data : ports) {
1343
22737
    ports_.insert(data);
1344
22737
    CHECK(!data->group_);
1345
22737
    data->group_ = shared_from_this();
1346
  }
1347
11388
}
1348
1349
22692
void SiblingGroup::Disentangle(MessagePortData* data) {
1350
45385
  auto self = shared_from_this();  // Keep alive until end of function.
1351
45384
  Mutex::ScopedLock lock(group_mutex_);
1352
22693
  ports_.erase(data);
1353
22691
  data->group_.reset();
1354
1355
22692
  data->AddToIncomingQueue(std::make_shared<Message>());
1356
  // If this is an anonymous group and there's another port, close it.
1357

22688
  if (size() == 1 && name_.empty())
1358
11344
    (*(ports_.begin()))->AddToIncomingQueue(std::make_shared<Message>());
1359
22693
}
1360
1361
4699
SiblingGroup::Map SiblingGroup::groups_;
1362
4699
Mutex SiblingGroup::groups_mutex_;
1363
1364
namespace {
1365
1366
444
static void SetDeserializerCreateObjectFunction(
1367
    const FunctionCallbackInfo<Value>& args) {
1368
444
  Environment* env = Environment::GetCurrent(args);
1369
888
  CHECK(args[0]->IsFunction());
1370
888
  env->set_messaging_deserialize_create_object(args[0].As<Function>());
1371
444
}
1372
1373
10714
static void MessageChannel(const FunctionCallbackInfo<Value>& args) {
1374
10714
  Environment* env = Environment::GetCurrent(args);
1375
10714
  if (!args.IsConstructCall()) {
1376
1
    THROW_ERR_CONSTRUCT_CALL_REQUIRED(env);
1377
1
    return;
1378
  }
1379
1380
21426
  Local<Context> context = args.This()->CreationContext();
1381
10713
  Context::Scope context_scope(context);
1382
1383
10713
  MessagePort* port1 = MessagePort::New(env, context);
1384
10713
  if (port1 == nullptr) return;
1385
10713
  MessagePort* port2 = MessagePort::New(env, context);
1386
10713
  if (port2 == nullptr) {
1387
    port1->Close();
1388
    return;
1389
  }
1390
1391
10713
  MessagePort::Entangle(port1, port2);
1392
1393
53565
  args.This()->Set(context, env->port1_string(), port1->object())
1394
      .Check();
1395
53565
  args.This()->Set(context, env->port2_string(), port2->object())
1396
      .Check();
1397
}
1398
1399
39
static void BroadcastChannel(const FunctionCallbackInfo<Value>& args) {
1400
117
  CHECK(args[0]->IsString());
1401
39
  Environment* env = Environment::GetCurrent(args);
1402
39
  Context::Scope context_scope(env->context());
1403
78
  Utf8Value name(env->isolate(), args[0]);
1404
  MessagePort* port =
1405
39
      MessagePort::New(env, env->context(), {}, SiblingGroup::Get(*name));
1406
39
  if (port != nullptr) {
1407
117
    args.GetReturnValue().Set(port->object());
1408
  }
1409
39
}
1410
1411
444
static void InitMessaging(Local<Object> target,
1412
                          Local<Value> unused,
1413
                          Local<Context> context,
1414
                          void* priv) {
1415
444
  Environment* env = Environment::GetCurrent(context);
1416
1417
  {
1418
888
    env->SetConstructorFunction(
1419
        target,
1420
        "MessageChannel",
1421
444
        env->NewFunctionTemplate(MessageChannel));
1422
  }
1423
1424
  {
1425
444
    Local<FunctionTemplate> t = env->NewFunctionTemplate(JSTransferable::New);
1426
888
    t->Inherit(BaseObject::GetConstructorTemplate(env));
1427
1332
    t->InstanceTemplate()->SetInternalFieldCount(
1428
444
        JSTransferable::kInternalFieldCount);
1429
444
    env->SetConstructorFunction(target, "JSTransferable", t);
1430
  }
1431
1432
444
  env->SetConstructorFunction(
1433
      target,
1434
      env->message_port_constructor_string(),
1435
444
      GetMessagePortConstructorTemplate(env));
1436
1437
  // These are not methods on the MessagePort prototype, because
1438
  // the browser equivalents do not provide them.
1439
444
  env->SetMethod(target, "stopMessagePort", MessagePort::Stop);
1440
444
  env->SetMethod(target, "checkMessagePort", MessagePort::CheckType);
1441
444
  env->SetMethod(target, "drainMessagePort", MessagePort::Drain);
1442
444
  env->SetMethod(target, "receiveMessageOnPort", MessagePort::ReceiveMessage);
1443
  env->SetMethod(target, "moveMessagePortToContext",
1444
444
                 MessagePort::MoveToContext);
1445
  env->SetMethod(target, "setDeserializerCreateObjectFunction",
1446
444
                 SetDeserializerCreateObjectFunction);
1447
444
  env->SetMethod(target, "broadcastChannel", BroadcastChannel);
1448
1449
  {
1450
888
    Local<Function> domexception = GetDOMException(context).ToLocalChecked();
1451
    target
1452
888
        ->Set(context,
1453
              FIXED_ONE_BYTE_STRING(env->isolate(), "DOMException"),
1454
1332
              domexception)
1455
        .Check();
1456
  }
1457
444
}
1458
1459
4621
static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1460
4621
  registry->Register(MessageChannel);
1461
4621
  registry->Register(BroadcastChannel);
1462
4621
  registry->Register(JSTransferable::New);
1463
4621
  registry->Register(MessagePort::New);
1464
4621
  registry->Register(MessagePort::PostMessage);
1465
4621
  registry->Register(MessagePort::Start);
1466
4621
  registry->Register(MessagePort::Stop);
1467
4621
  registry->Register(MessagePort::CheckType);
1468
4621
  registry->Register(MessagePort::Drain);
1469
4621
  registry->Register(MessagePort::ReceiveMessage);
1470
4621
  registry->Register(MessagePort::MoveToContext);
1471
4621
  registry->Register(SetDeserializerCreateObjectFunction);
1472
4621
}
1473
1474
}  // anonymous namespace
1475
1476
}  // namespace worker
1477
}  // namespace node
1478
1479
4691
NODE_MODULE_CONTEXT_AWARE_INTERNAL(messaging, node::worker::InitMessaging)
1480

18718
NODE_MODULE_EXTERNAL_REFERENCE(messaging,
1481
                               node::worker::RegisterExternalReferences)