blob: c9b5e3244799757da080751f51c31813157a19c8 [file] [log] [blame]
Anna Henningsen018d6182018-06-20 15:10:061#include "debug_utils.h"
Anna Henningsene7a23672017-09-05 20:38:322#include "node_messaging.h"
3#include "node_internals.h"
4#include "node_buffer.h"
5#include "node_errors.h"
6#include "util.h"
7#include "util-inl.h"
8#include "async_wrap.h"
9#include "async_wrap-inl.h"
10
11using v8::Array;
12using v8::ArrayBuffer;
13using v8::ArrayBufferCreationMode;
14using v8::Context;
15using v8::EscapableHandleScope;
16using v8::Exception;
17using v8::Function;
18using v8::FunctionCallbackInfo;
19using v8::FunctionTemplate;
20using v8::HandleScope;
21using v8::Isolate;
22using v8::Just;
23using v8::Local;
24using v8::Maybe;
25using v8::MaybeLocal;
26using v8::Nothing;
27using v8::Object;
Anna Henningsenb0404042018-05-13 17:39:3228using v8::SharedArrayBuffer;
Anna Henningsene7a23672017-09-05 20:38:3229using v8::String;
30using v8::Value;
31using v8::ValueDeserializer;
32using v8::ValueSerializer;
33
34namespace node {
35namespace worker {
36
37Message::Message(MallocedBuffer<char>&& buffer)
38 : main_message_buf_(std::move(buffer)) {}
39
40namespace {
41
42// This is used to tell V8 how to read transferred host objects, like other
43// `MessagePort`s and `SharedArrayBuffer`s, and make new JS objects out of them.
44class DeserializerDelegate : public ValueDeserializer::Delegate {
45 public:
Anna Henningsen749a13b2017-10-07 21:39:0246 DeserializerDelegate(Message* m,
47 Environment* env,
Anna Henningsenb0404042018-05-13 17:39:3248 const std::vector<MessagePort*>& message_ports,
49 const std::vector<Local<SharedArrayBuffer>>&
50 shared_array_buffers)
Daniel Bevenius19dae6b2018-05-23 11:10:5351 : message_ports_(message_ports),
Anna Henningsenb0404042018-05-13 17:39:3252 shared_array_buffers_(shared_array_buffers) {}
Anna Henningsen749a13b2017-10-07 21:39:0253
54 MaybeLocal<Object> ReadHostObject(Isolate* isolate) override {
55 // Currently, only MessagePort hosts objects are supported, so identifying
56 // by the index in the message's MessagePort array is sufficient.
57 uint32_t id;
58 if (!deserializer->ReadUint32(&id))
59 return MaybeLocal<Object>();
60 CHECK_LE(id, message_ports_.size());
Anna Henningsen0df031a2017-09-01 15:03:4161 return message_ports_[id]->object(isolate);
Anna Henningsen749a13b2017-10-07 21:39:0262 };
Anna Henningsene7a23672017-09-05 20:38:3263
Anna Henningsenb0404042018-05-13 17:39:3264 MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
65 Isolate* isolate, uint32_t clone_id) override {
66 CHECK_LE(clone_id, shared_array_buffers_.size());
67 return shared_array_buffers_[clone_id];
68 }
69
Anna Henningsene7a23672017-09-05 20:38:3270 ValueDeserializer* deserializer = nullptr;
71
72 private:
Anna Henningsen749a13b2017-10-07 21:39:0273 const std::vector<MessagePort*>& message_ports_;
Anna Henningsenb0404042018-05-13 17:39:3274 const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers_;
Anna Henningsene7a23672017-09-05 20:38:3275};
76
77} // anonymous namespace
78
79MaybeLocal<Value> Message::Deserialize(Environment* env,
80 Local<Context> context) {
81 EscapableHandleScope handle_scope(env->isolate());
82 Context::Scope context_scope(context);
83
Anna Henningsen749a13b2017-10-07 21:39:0284 // Create all necessary MessagePort handles.
85 std::vector<MessagePort*> ports(message_ports_.size());
86 for (uint32_t i = 0; i < message_ports_.size(); ++i) {
87 ports[i] = MessagePort::New(env,
88 context,
89 std::move(message_ports_[i]));
90 if (ports[i] == nullptr) {
91 for (MessagePort* port : ports) {
92 // This will eventually release the MessagePort object itself.
93 port->Close();
94 }
95 return MaybeLocal<Value>();
96 }
97 }
98 message_ports_.clear();
99
Anna Henningsenb0404042018-05-13 17:39:32100 std::vector<Local<SharedArrayBuffer>> shared_array_buffers;
Brandon Smith13340d42018-10-07 01:09:29101 // Attach all transferred SharedArrayBuffers to their new Isolate.
Anna Henningsenb0404042018-05-13 17:39:32102 for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) {
103 Local<SharedArrayBuffer> sab;
104 if (!shared_array_buffers_[i]->GetSharedArrayBuffer(env, context)
105 .ToLocal(&sab))
106 return MaybeLocal<Value>();
107 shared_array_buffers.push_back(sab);
108 }
109 shared_array_buffers_.clear();
110
111 DeserializerDelegate delegate(this, env, ports, shared_array_buffers);
Anna Henningsene7a23672017-09-05 20:38:32112 ValueDeserializer deserializer(
113 env->isolate(),
114 reinterpret_cast<const uint8_t*>(main_message_buf_.data),
115 main_message_buf_.size,
116 &delegate);
117 delegate.deserializer = &deserializer;
118
Brandon Smith13340d42018-10-07 01:09:29119 // Attach all transferred ArrayBuffers to their new Isolate.
Anna Henningsene7a23672017-09-05 20:38:32120 for (uint32_t i = 0; i < array_buffer_contents_.size(); ++i) {
121 Local<ArrayBuffer> ab =
122 ArrayBuffer::New(env->isolate(),
123 array_buffer_contents_[i].release(),
124 array_buffer_contents_[i].size,
125 ArrayBufferCreationMode::kInternalized);
126 deserializer.TransferArrayBuffer(i, ab);
127 }
128 array_buffer_contents_.clear();
129
130 if (deserializer.ReadHeader(context).IsNothing())
131 return MaybeLocal<Value>();
132 return handle_scope.Escape(
133 deserializer.ReadValue(context).FromMaybe(Local<Value>()));
134}
135
Anna Henningsenb0404042018-05-13 17:39:32136void Message::AddSharedArrayBuffer(
137 SharedArrayBufferMetadataReference reference) {
138 shared_array_buffers_.push_back(reference);
139}
140
Anna Henningsen749a13b2017-10-07 21:39:02141void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) {
142 message_ports_.emplace_back(std::move(data));
143}
144
Anna Henningsene7a23672017-09-05 20:38:32145namespace {
146
Timothy Guf374d6a2018-06-25 03:10:37147void ThrowDataCloneException(Environment* env, Local<String> message) {
Timothy Gu5f3bdb02018-06-25 04:48:48148 Local<Value> argv[] = {
149 message,
150 FIXED_ONE_BYTE_STRING(env->isolate(), "DataCloneError")
151 };
152 Local<Value> exception;
153 Local<Function> domexception_ctor = env->domexception_function();
154 CHECK(!domexception_ctor.IsEmpty());
155 if (!domexception_ctor->NewInstance(env->context(), arraysize(argv), argv)
156 .ToLocal(&exception)) {
157 return;
158 }
159 env->isolate()->ThrowException(exception);
160}
161
Anna Henningsene7a23672017-09-05 20:38:32162// This tells V8 how to serialize objects that it does not understand
163// (e.g. C++ objects) into the output buffer, in a way that our own
164// DeserializerDelegate understands how to unpack.
165class SerializerDelegate : public ValueSerializer::Delegate {
166 public:
167 SerializerDelegate(Environment* env, Local<Context> context, Message* m)
168 : env_(env), context_(context), msg_(m) {}
169
170 void ThrowDataCloneError(Local<String> message) override {
Timothy Guf374d6a2018-06-25 03:10:37171 ThrowDataCloneException(env_, message);
Anna Henningsene7a23672017-09-05 20:38:32172 }
173
Anna Henningsen749a13b2017-10-07 21:39:02174 Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override {
175 if (env_->message_port_constructor_template()->HasInstance(object)) {
176 return WriteMessagePort(Unwrap<MessagePort>(object));
177 }
178
179 THROW_ERR_CANNOT_TRANSFER_OBJECT(env_);
180 return Nothing<bool>();
181 }
182
Anna Henningsenb0404042018-05-13 17:39:32183 Maybe<uint32_t> GetSharedArrayBufferId(
184 Isolate* isolate,
185 Local<SharedArrayBuffer> shared_array_buffer) override {
186 uint32_t i;
187 for (i = 0; i < seen_shared_array_buffers_.size(); ++i) {
188 if (seen_shared_array_buffers_[i] == shared_array_buffer)
189 return Just(i);
190 }
191
192 auto reference = SharedArrayBufferMetadata::ForSharedArrayBuffer(
193 env_,
194 context_,
195 shared_array_buffer);
196 if (!reference) {
197 return Nothing<uint32_t>();
198 }
199 seen_shared_array_buffers_.push_back(shared_array_buffer);
200 msg_->AddSharedArrayBuffer(reference);
201 return Just(i);
202 }
203
Anna Henningsen749a13b2017-10-07 21:39:02204 void Finish() {
205 // Only close the MessagePort handles and actually transfer them
206 // once we know that serialization succeeded.
207 for (MessagePort* port : ports_) {
208 port->Close();
209 msg_->AddMessagePort(port->Detach());
210 }
211 }
212
Anna Henningsene7a23672017-09-05 20:38:32213 ValueSerializer* serializer = nullptr;
214
215 private:
Anna Henningsen749a13b2017-10-07 21:39:02216 Maybe<bool> WriteMessagePort(MessagePort* port) {
217 for (uint32_t i = 0; i < ports_.size(); i++) {
218 if (ports_[i] == port) {
219 serializer->WriteUint32(i);
220 return Just(true);
221 }
222 }
223
224 THROW_ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST(env_);
225 return Nothing<bool>();
226 }
227
Anna Henningsene7a23672017-09-05 20:38:32228 Environment* env_;
229 Local<Context> context_;
230 Message* msg_;
Anna Henningsenb0404042018-05-13 17:39:32231 std::vector<Local<SharedArrayBuffer>> seen_shared_array_buffers_;
Anna Henningsen749a13b2017-10-07 21:39:02232 std::vector<MessagePort*> ports_;
Anna Henningsene7a23672017-09-05 20:38:32233
234 friend class worker::Message;
235};
236
Brandon Smith13340d42018-10-07 01:09:29237} // anonymous namespace
Anna Henningsene7a23672017-09-05 20:38:32238
239Maybe<bool> Message::Serialize(Environment* env,
240 Local<Context> context,
241 Local<Value> input,
Timothy Guf374d6a2018-06-25 03:10:37242 Local<Value> transfer_list_v,
243 Local<Object> source_port) {
Anna Henningsene7a23672017-09-05 20:38:32244 HandleScope handle_scope(env->isolate());
245 Context::Scope context_scope(context);
246
247 // Verify that we're not silently overwriting an existing message.
248 CHECK(main_message_buf_.is_empty());
249
250 SerializerDelegate delegate(env, context, this);
251 ValueSerializer serializer(env->isolate(), &delegate);
252 delegate.serializer = &serializer;
253
254 std::vector<Local<ArrayBuffer>> array_buffers;
255 if (transfer_list_v->IsArray()) {
256 Local<Array> transfer_list = transfer_list_v.As<Array>();
257 uint32_t length = transfer_list->Length();
258 for (uint32_t i = 0; i < length; ++i) {
259 Local<Value> entry;
260 if (!transfer_list->Get(context, i).ToLocal(&entry))
261 return Nothing<bool>();
Anna Henningsen749a13b2017-10-07 21:39:02262 // Currently, we support ArrayBuffers and MessagePorts.
Anna Henningsene7a23672017-09-05 20:38:32263 if (entry->IsArrayBuffer()) {
264 Local<ArrayBuffer> ab = entry.As<ArrayBuffer>();
265 // If we cannot render the ArrayBuffer unusable in this Isolate and
266 // take ownership of its memory, copying the buffer will have to do.
267 if (!ab->IsNeuterable() || ab->IsExternal())
268 continue;
269 // We simply use the array index in the `array_buffers` list as the
270 // ID that we write into the serialized buffer.
271 uint32_t id = array_buffers.size();
272 array_buffers.push_back(ab);
273 serializer.TransferArrayBuffer(id, ab);
274 continue;
Anna Henningsen749a13b2017-10-07 21:39:02275 } else if (env->message_port_constructor_template()
276 ->HasInstance(entry)) {
Timothy Guf374d6a2018-06-25 03:10:37277 // Check if the source MessagePort is being transferred.
278 if (!source_port.IsEmpty() && entry == source_port) {
279 ThrowDataCloneException(
280 env,
281 FIXED_ONE_BYTE_STRING(env->isolate(),
282 "Transfer list contains source port"));
283 return Nothing<bool>();
284 }
Anna Henningsen749a13b2017-10-07 21:39:02285 MessagePort* port = Unwrap<MessagePort>(entry.As<Object>());
Timothy Guf374d6a2018-06-25 03:10:37286 if (port == nullptr || port->IsDetached()) {
287 ThrowDataCloneException(
288 env,
289 FIXED_ONE_BYTE_STRING(
290 env->isolate(),
291 "MessagePort in transfer list is already detached"));
292 return Nothing<bool>();
293 }
Anna Henningsen749a13b2017-10-07 21:39:02294 delegate.ports_.push_back(port);
295 continue;
Anna Henningsene7a23672017-09-05 20:38:32296 }
297
298 THROW_ERR_INVALID_TRANSFER_OBJECT(env);
299 return Nothing<bool>();
300 }
301 }
302
303 serializer.WriteHeader();
304 if (serializer.WriteValue(context, input).IsNothing()) {
305 return Nothing<bool>();
306 }
307
308 for (Local<ArrayBuffer> ab : array_buffers) {
309 // If serialization succeeded, we want to take ownership of
310 // (a.k.a. externalize) the underlying memory region and render
311 // it inaccessible in this Isolate.
312 ArrayBuffer::Contents contents = ab->Externalize();
313 ab->Neuter();
314 array_buffer_contents_.push_back(
315 MallocedBuffer<char> { static_cast<char*>(contents.Data()),
316 contents.ByteLength() });
317 }
318
Anna Henningsen749a13b2017-10-07 21:39:02319 delegate.Finish();
320
Anna Henningsene7a23672017-09-05 20:38:32321 // The serializer gave us a buffer allocated using `malloc()`.
322 std::pair<uint8_t*, size_t> data = serializer.Release();
323 main_message_buf_ =
324 MallocedBuffer<char>(reinterpret_cast<char*>(data.first), data.second);
325 return Just(true);
326}
327
Anna Henningsen57e30152018-06-10 14:40:13328void Message::MemoryInfo(MemoryTracker* tracker) const {
Anna Henningsen57e30152018-06-10 14:40:13329 tracker->TrackField("array_buffer_contents", array_buffer_contents_);
330 tracker->TrackFieldWithSize("shared_array_buffers",
331 shared_array_buffers_.size() * sizeof(shared_array_buffers_[0]));
332 tracker->TrackField("message_ports", message_ports_);
333}
334
Anna Henningsene7a23672017-09-05 20:38:32335MessagePortData::MessagePortData(MessagePort* owner) : owner_(owner) { }
336
337MessagePortData::~MessagePortData() {
338 CHECK_EQ(owner_, nullptr);
339 Disentangle();
340}
341
Anna Henningsen57e30152018-06-10 14:40:13342void MessagePortData::MemoryInfo(MemoryTracker* tracker) const {
343 Mutex::ScopedLock lock(mutex_);
Anna Henningsen57e30152018-06-10 14:40:13344 tracker->TrackField("incoming_messages", incoming_messages_);
345}
346
Anna Henningsene7a23672017-09-05 20:38:32347void MessagePortData::AddToIncomingQueue(Message&& message) {
348 // This function will be called by other threads.
349 Mutex::ScopedLock lock(mutex_);
350 incoming_messages_.emplace_back(std::move(message));
351
Anna Henningsen018d6182018-06-20 15:10:06352 if (owner_ != nullptr) {
353 Debug(owner_, "Adding message to incoming queue");
Anna Henningsene7a23672017-09-05 20:38:32354 owner_->TriggerAsync();
Anna Henningsen018d6182018-06-20 15:10:06355 }
Anna Henningsene7a23672017-09-05 20:38:32356}
357
358bool MessagePortData::IsSiblingClosed() const {
359 Mutex::ScopedLock lock(*sibling_mutex_);
360 return sibling_ == nullptr;
361}
362
363void MessagePortData::Entangle(MessagePortData* a, MessagePortData* b) {
364 CHECK_EQ(a->sibling_, nullptr);
365 CHECK_EQ(b->sibling_, nullptr);
366 a->sibling_ = b;
367 b->sibling_ = a;
368 a->sibling_mutex_ = b->sibling_mutex_;
369}
370
371void MessagePortData::PingOwnerAfterDisentanglement() {
372 Mutex::ScopedLock lock(mutex_);
373 if (owner_ != nullptr)
374 owner_->TriggerAsync();
375}
376
377void MessagePortData::Disentangle() {
378 // Grab a copy of the sibling mutex, then replace it so that each sibling
379 // has its own sibling_mutex_ now.
380 std::shared_ptr<Mutex> sibling_mutex = sibling_mutex_;
381 Mutex::ScopedLock sibling_lock(*sibling_mutex);
382 sibling_mutex_ = std::make_shared<Mutex>();
383
384 MessagePortData* sibling = sibling_;
385 if (sibling_ != nullptr) {
386 sibling_->sibling_ = nullptr;
387 sibling_ = nullptr;
388 }
389
390 // We close MessagePorts after disentanglement, so we trigger the
391 // corresponding uv_async_t to let them know that this happened.
392 PingOwnerAfterDisentanglement();
393 if (sibling != nullptr) {
394 sibling->PingOwnerAfterDisentanglement();
395 }
396}
397
398MessagePort::~MessagePort() {
399 if (data_)
400 data_->owner_ = nullptr;
401}
402
403MessagePort::MessagePort(Environment* env,
404 Local<Context> context,
405 Local<Object> wrap)
406 : HandleWrap(env,
407 wrap,
408 reinterpret_cast<uv_handle_t*>(new uv_async_t()),
409 AsyncWrap::PROVIDER_MESSAGEPORT),
410 data_(new MessagePortData(this)) {
411 auto onmessage = [](uv_async_t* handle) {
412 // Called when data has been put into the queue.
413 MessagePort* channel = static_cast<MessagePort*>(handle->data);
414 channel->OnMessage();
415 };
416 CHECK_EQ(uv_async_init(env->event_loop(),
417 async(),
418 onmessage), 0);
419 async()->data = static_cast<void*>(this);
420
421 Local<Value> fn;
Anna Henningsen2d65e672018-09-23 17:10:54422 if (!wrap->Get(context, env->oninit_symbol()).ToLocal(&fn))
Anna Henningsene7a23672017-09-05 20:38:32423 return;
424
425 if (fn->IsFunction()) {
426 Local<Function> init = fn.As<Function>();
427 USE(init->Call(context, wrap, 0, nullptr));
428 }
Anna Henningsen018d6182018-06-20 15:10:06429
430 Debug(this, "Created message port");
Anna Henningsene7a23672017-09-05 20:38:32431}
432
433void MessagePort::AddToIncomingQueue(Message&& message) {
434 data_->AddToIncomingQueue(std::move(message));
435}
436
437uv_async_t* MessagePort::async() {
438 return reinterpret_cast<uv_async_t*>(GetHandle());
439}
440
Timothy Guf374d6a2018-06-25 03:10:37441bool MessagePort::IsDetached() const {
442 return data_ == nullptr || IsHandleClosing();
443}
444
Anna Henningsene7a23672017-09-05 20:38:32445void MessagePort::TriggerAsync() {
Anna Henningsen22c826f2018-06-07 12:43:45446 if (IsHandleClosing()) return;
Anna Henningsene7a23672017-09-05 20:38:32447 CHECK_EQ(uv_async_send(async()), 0);
448}
449
Anna Henningsen22c826f2018-06-07 12:43:45450void MessagePort::Close(v8::Local<v8::Value> close_callback) {
Anna Henningsen018d6182018-06-20 15:10:06451 Debug(this, "Closing message port, data set = %d", static_cast<int>(!!data_));
452
Anna Henningsen22c826f2018-06-07 12:43:45453 if (data_) {
454 // Wrap this call with accessing the mutex, so that TriggerAsync()
455 // can check IsHandleClosing() without race conditions.
456 Mutex::ScopedLock sibling_lock(data_->mutex_);
457 HandleWrap::Close(close_callback);
458 } else {
459 HandleWrap::Close(close_callback);
460 }
461}
462
Anna Henningsene7a23672017-09-05 20:38:32463void MessagePort::New(const FunctionCallbackInfo<Value>& args) {
464 Environment* env = Environment::GetCurrent(args);
465 if (!args.IsConstructCall()) {
466 THROW_ERR_CONSTRUCT_CALL_REQUIRED(env);
467 return;
468 }
469
470 Local<Context> context = args.This()->CreationContext();
471 Context::Scope context_scope(context);
472
473 new MessagePort(env, context, args.This());
474}
475
476MessagePort* MessagePort::New(
477 Environment* env,
478 Local<Context> context,
479 std::unique_ptr<MessagePortData> data) {
480 Context::Scope context_scope(context);
481 Local<Function> ctor;
482 if (!GetMessagePortConstructor(env, context).ToLocal(&ctor))
483 return nullptr;
Anna Henningsene7a23672017-09-05 20:38:32484
485 // Construct a new instance, then assign the listener instance and possibly
486 // the MessagePortData to it.
487 Local<Object> instance;
488 if (!ctor->NewInstance(context).ToLocal(&instance))
489 return nullptr;
Anna Henningsend102a852018-09-23 17:26:30490 MessagePort* port = Unwrap<MessagePort>(instance);
491 CHECK_NOT_NULL(port);
Anna Henningsene7a23672017-09-05 20:38:32492 if (data) {
493 port->Detach();
494 port->data_ = std::move(data);
495 port->data_->owner_ = port;
496 // If the existing MessagePortData object had pending messages, this is
497 // the easiest way to run that queue.
498 port->TriggerAsync();
499 }
500 return port;
501}
502
503void MessagePort::OnMessage() {
Anna Henningsen018d6182018-06-20 15:10:06504 Debug(this, "Running MessagePort::OnMessage()");
Anna Henningsene7a23672017-09-05 20:38:32505 HandleScope handle_scope(env()->isolate());
Anna Henningsen0df031a2017-09-01 15:03:41506 Local<Context> context = object(env()->isolate())->CreationContext();
Anna Henningsene7a23672017-09-05 20:38:32507
508 // data_ can only ever be modified by the owner thread, so no need to lock.
509 // However, the message port may be transferred while it is processing
510 // messages, so we need to check that this handle still owns its `data_` field
511 // on every iteration.
512 while (data_) {
513 Message received;
514 {
515 // Get the head of the message queue.
516 Mutex::ScopedLock lock(data_->mutex_);
Anna Henningsen0df031a2017-09-01 15:03:41517
518 if (stop_event_loop_) {
Anna Henningsen018d6182018-06-20 15:10:06519 Debug(this, "MessagePort stops loop as requested");
Anna Henningsen0df031a2017-09-01 15:03:41520 CHECK(!data_->receiving_messages_);
521 uv_stop(env()->event_loop());
522 break;
523 }
524
Anna Henningsen018d6182018-06-20 15:10:06525 Debug(this, "MessagePort has message, receiving = %d",
526 static_cast<int>(data_->receiving_messages_));
527
Anna Henningsene7a23672017-09-05 20:38:32528 if (!data_->receiving_messages_)
529 break;
530 if (data_->incoming_messages_.empty())
531 break;
532 received = std::move(data_->incoming_messages_.front());
533 data_->incoming_messages_.pop_front();
534 }
535
536 if (!env()->can_call_into_js()) {
Anna Henningsen018d6182018-06-20 15:10:06537 Debug(this, "MessagePort drains queue because !can_call_into_js()");
Anna Henningsene7a23672017-09-05 20:38:32538 // In this case there is nothing to do but to drain the current queue.
539 continue;
540 }
541
542 {
543 // Call the JS .onmessage() callback.
544 HandleScope handle_scope(env()->isolate());
545 Context::Scope context_scope(context);
546 Local<Value> args[] = {
547 received.Deserialize(env(), context).FromMaybe(Local<Value>())
548 };
549
550 if (args[0].IsEmpty() ||
Anna Henningsene7a23672017-09-05 20:38:32551 MakeCallback(env()->onmessage_string(), 1, args).IsEmpty()) {
552 // Re-schedule OnMessage() execution in case of failure.
553 if (data_)
554 TriggerAsync();
555 return;
556 }
557 }
558 }
559
560 if (data_ && data_->IsSiblingClosed()) {
561 Close();
562 }
563}
564
565bool MessagePort::IsSiblingClosed() const {
566 CHECK(data_);
567 return data_->IsSiblingClosed();
568}
569
570void MessagePort::OnClose() {
Anna Henningsen018d6182018-06-20 15:10:06571 Debug(this, "MessagePort::OnClose()");
Anna Henningsene7a23672017-09-05 20:38:32572 if (data_) {
573 data_->owner_ = nullptr;
574 data_->Disentangle();
575 }
576 data_.reset();
577 delete async();
578}
579
580std::unique_ptr<MessagePortData> MessagePort::Detach() {
581 Mutex::ScopedLock lock(data_->mutex_);
582 data_->owner_ = nullptr;
583 return std::move(data_);
584}
585
586
Timothy Guf374d6a2018-06-25 03:10:37587Maybe<bool> MessagePort::PostMessage(Environment* env,
588 Local<Value> message_v,
589 Local<Value> transfer_v) {
590 Isolate* isolate = env->isolate();
591 Local<Object> obj = object(isolate);
592 Local<Context> context = obj->CreationContext();
Anna Henningsene7a23672017-09-05 20:38:32593
Anna Henningsene7a23672017-09-05 20:38:32594 Message msg;
Timothy Guf374d6a2018-06-25 03:10:37595
596 // Per spec, we need to both check if transfer list has the source port, and
597 // serialize the input message, even if the MessagePort is closed or detached.
598
599 Maybe<bool> serialization_maybe =
600 msg.Serialize(env, context, message_v, transfer_v, obj);
601 if (data_ == nullptr) {
602 return serialization_maybe;
Anna Henningsene7a23672017-09-05 20:38:32603 }
Timothy Guf374d6a2018-06-25 03:10:37604 if (serialization_maybe.IsNothing()) {
605 return Nothing<bool>();
606 }
607
608 Mutex::ScopedLock lock(*data_->sibling_mutex_);
609 bool doomed = false;
610
611 // Check if the target port is posted to itself.
612 if (data_->sibling_ != nullptr) {
613 for (const auto& port_data : msg.message_ports()) {
614 if (data_->sibling_ == port_data.get()) {
615 doomed = true;
616 ProcessEmitWarning(env, "The target port was posted to itself, and "
617 "the communication channel was lost");
618 break;
619 }
620 }
621 }
622
623 if (data_->sibling_ == nullptr || doomed)
624 return Just(true);
625
626 data_->sibling_->AddToIncomingQueue(std::move(msg));
627 return Just(true);
Anna Henningsene7a23672017-09-05 20:38:32628}
629
630void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) {
631 Environment* env = Environment::GetCurrent(args);
Anna Henningsene7a23672017-09-05 20:38:32632 if (args.Length() == 0) {
633 return THROW_ERR_MISSING_ARGS(env, "Not enough arguments to "
634 "MessagePort.postMessage");
635 }
Timothy Guf374d6a2018-06-25 03:10:37636
637 MessagePort* port = Unwrap<MessagePort>(args.This());
638 // Even if the backing MessagePort object has already been deleted, we still
639 // want to serialize the message to ensure spec-compliant behavior w.r.t.
640 // transfers.
641 if (port == nullptr) {
642 Message msg;
643 Local<Object> obj = args.This();
644 Local<Context> context = obj->CreationContext();
645 USE(msg.Serialize(env, context, args[0], args[1], obj));
646 return;
647 }
648
649 port->PostMessage(env, args[0], args[1]);
Anna Henningsene7a23672017-09-05 20:38:32650}
651
652void MessagePort::Start() {
653 Mutex::ScopedLock lock(data_->mutex_);
Anna Henningsen018d6182018-06-20 15:10:06654 Debug(this, "Start receiving messages");
Anna Henningsene7a23672017-09-05 20:38:32655 data_->receiving_messages_ = true;
656 if (!data_->incoming_messages_.empty())
657 TriggerAsync();
658}
659
660void MessagePort::Stop() {
661 Mutex::ScopedLock lock(data_->mutex_);
Anna Henningsen018d6182018-06-20 15:10:06662 Debug(this, "Stop receiving messages");
Anna Henningsene7a23672017-09-05 20:38:32663 data_->receiving_messages_ = false;
664}
665
Anna Henningsen0df031a2017-09-01 15:03:41666void MessagePort::StopEventLoop() {
667 Mutex::ScopedLock lock(data_->mutex_);
668 data_->receiving_messages_ = false;
669 stop_event_loop_ = true;
670
Anna Henningsen018d6182018-06-20 15:10:06671 Debug(this, "Received StopEventLoop request");
Anna Henningsen0df031a2017-09-01 15:03:41672 TriggerAsync();
673}
674
Anna Henningsene7a23672017-09-05 20:38:32675void MessagePort::Start(const FunctionCallbackInfo<Value>& args) {
676 Environment* env = Environment::GetCurrent(args);
677 MessagePort* port;
678 ASSIGN_OR_RETURN_UNWRAP(&port, args.This());
679 if (!port->data_) {
680 THROW_ERR_CLOSED_MESSAGE_PORT(env);
681 return;
682 }
683 port->Start();
684}
685
686void MessagePort::Stop(const FunctionCallbackInfo<Value>& args) {
687 Environment* env = Environment::GetCurrent(args);
688 MessagePort* port;
689 ASSIGN_OR_RETURN_UNWRAP(&port, args.This());
690 if (!port->data_) {
691 THROW_ERR_CLOSED_MESSAGE_PORT(env);
692 return;
693 }
694 port->Stop();
695}
696
Anna Henningsen0df031a2017-09-01 15:03:41697void MessagePort::Drain(const FunctionCallbackInfo<Value>& args) {
698 MessagePort* port;
699 ASSIGN_OR_RETURN_UNWRAP(&port, args.This());
700 port->OnMessage();
701}
702
Anna Henningsene7a23672017-09-05 20:38:32703void MessagePort::Entangle(MessagePort* a, MessagePort* b) {
704 Entangle(a, b->data_.get());
705}
706
707void MessagePort::Entangle(MessagePort* a, MessagePortData* b) {
708 MessagePortData::Entangle(a->data_.get(), b);
709}
710
711MaybeLocal<Function> GetMessagePortConstructor(
712 Environment* env, Local<Context> context) {
713 // Factor generating the MessagePort JS constructor into its own piece
714 // of code, because it is needed early on in the child environment setup.
715 Local<FunctionTemplate> templ = env->message_port_constructor_template();
716 if (!templ.IsEmpty())
717 return templ->GetFunction(context);
718
719 {
720 Local<FunctionTemplate> m = env->NewFunctionTemplate(MessagePort::New);
721 m->SetClassName(env->message_port_constructor_string());
722 m->InstanceTemplate()->SetInternalFieldCount(1);
Anna Henningsend527dde2018-09-23 17:24:33723 m->Inherit(HandleWrap::GetConstructorTemplate(env));
Anna Henningsene7a23672017-09-05 20:38:32724
725 env->SetProtoMethod(m, "postMessage", MessagePort::PostMessage);
726 env->SetProtoMethod(m, "start", MessagePort::Start);
727 env->SetProtoMethod(m, "stop", MessagePort::Stop);
Anna Henningsen0df031a2017-09-01 15:03:41728 env->SetProtoMethod(m, "drain", MessagePort::Drain);
Anna Henningsene7a23672017-09-05 20:38:32729
730 env->set_message_port_constructor_template(m);
731 }
732
733 return GetMessagePortConstructor(env, context);
734}
735
736namespace {
737
738static void MessageChannel(const FunctionCallbackInfo<Value>& args) {
739 Environment* env = Environment::GetCurrent(args);
740 if (!args.IsConstructCall()) {
741 THROW_ERR_CONSTRUCT_CALL_REQUIRED(env);
742 return;
743 }
744
745 Local<Context> context = args.This()->CreationContext();
746 Context::Scope context_scope(context);
747
748 MessagePort* port1 = MessagePort::New(env, context);
749 MessagePort* port2 = MessagePort::New(env, context);
750 MessagePort::Entangle(port1, port2);
751
752 args.This()->Set(env->context(), env->port1_string(), port1->object())
753 .FromJust();
754 args.This()->Set(env->context(), env->port2_string(), port2->object())
755 .FromJust();
756}
757
Timothy Gu5f3bdb02018-06-25 04:48:48758static void RegisterDOMException(const FunctionCallbackInfo<Value>& args) {
759 Environment* env = Environment::GetCurrent(args);
760 CHECK_EQ(args.Length(), 1);
761 CHECK(args[0]->IsFunction());
762 env->set_domexception_function(args[0].As<Function>());
763}
764
Anna Henningsene7a23672017-09-05 20:38:32765static void InitMessaging(Local<Object> target,
766 Local<Value> unused,
767 Local<Context> context,
768 void* priv) {
769 Environment* env = Environment::GetCurrent(context);
770
771 {
772 Local<String> message_channel_string =
773 FIXED_ONE_BYTE_STRING(env->isolate(), "MessageChannel");
774 Local<FunctionTemplate> templ = env->NewFunctionTemplate(MessageChannel);
775 templ->SetClassName(message_channel_string);
776 target->Set(env->context(),
777 message_channel_string,
778 templ->GetFunction(context).ToLocalChecked()).FromJust();
779 }
780
781 target->Set(context,
782 env->message_port_constructor_string(),
783 GetMessagePortConstructor(env, context).ToLocalChecked())
784 .FromJust();
Timothy Gu5f3bdb02018-06-25 04:48:48785
786 env->SetMethod(target, "registerDOMException", RegisterDOMException);
Anna Henningsene7a23672017-09-05 20:38:32787}
788
789} // anonymous namespace
790
791} // namespace worker
792} // namespace node
793
794NODE_MODULE_CONTEXT_AWARE_INTERNAL(messaging, node::worker::InitMessaging)