Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 1 | #include "node_messaging.h" |
Joyee Cheung | 7824280 | 2018-12-31 15:18:08 | [diff] [blame] | 2 | #include "async_wrap-inl.h" |
| 3 | #include "async_wrap.h" |
| 4 | #include "debug_utils.h" |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 5 | #include "node_buffer.h" |
| 6 | #include "node_errors.h" |
Joyee Cheung | 7824280 | 2018-12-31 15:18:08 | [diff] [blame] | 7 | #include "node_process.h" |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 8 | #include "util-inl.h" |
Joyee Cheung | 7824280 | 2018-12-31 15:18:08 | [diff] [blame] | 9 | #include "util.h" |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 10 | |
| 11 | using v8::Array; |
| 12 | using v8::ArrayBuffer; |
| 13 | using v8::ArrayBufferCreationMode; |
| 14 | using v8::Context; |
| 15 | using v8::EscapableHandleScope; |
| 16 | using v8::Exception; |
| 17 | using v8::Function; |
| 18 | using v8::FunctionCallbackInfo; |
| 19 | using v8::FunctionTemplate; |
| 20 | using v8::HandleScope; |
| 21 | using v8::Isolate; |
| 22 | using v8::Just; |
| 23 | using v8::Local; |
| 24 | using v8::Maybe; |
| 25 | using v8::MaybeLocal; |
| 26 | using v8::Nothing; |
| 27 | using v8::Object; |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 28 | using v8::SharedArrayBuffer; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 29 | using v8::String; |
| 30 | using v8::Value; |
| 31 | using v8::ValueDeserializer; |
| 32 | using v8::ValueSerializer; |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 33 | using v8::WasmCompiledModule; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 34 | |
| 35 | namespace node { |
| 36 | namespace worker { |
| 37 | |
| 38 | Message::Message(MallocedBuffer<char>&& buffer) |
| 39 | : main_message_buf_(std::move(buffer)) {} |
| 40 | |
| 41 | namespace { |
| 42 | |
| 43 | // This is used to tell V8 how to read transferred host objects, like other |
| 44 | // `MessagePort`s and `SharedArrayBuffer`s, and make new JS objects out of them. |
| 45 | class DeserializerDelegate : public ValueDeserializer::Delegate { |
| 46 | public: |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 47 | DeserializerDelegate( |
| 48 | Message* m, |
| 49 | Environment* env, |
| 50 | const std::vector<MessagePort*>& message_ports, |
| 51 | const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers, |
| 52 | const std::vector<WasmCompiledModule::TransferrableModule>& wasm_modules) |
| 53 | : message_ports_(message_ports), |
| 54 | shared_array_buffers_(shared_array_buffers), |
| 55 | wasm_modules_(wasm_modules) {} |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 56 | |
| 57 | MaybeLocal<Object> ReadHostObject(Isolate* isolate) override { |
| 58 | // Currently, only MessagePort hosts objects are supported, so identifying |
| 59 | // by the index in the message's MessagePort array is sufficient. |
| 60 | uint32_t id; |
| 61 | if (!deserializer->ReadUint32(&id)) |
| 62 | return MaybeLocal<Object>(); |
| 63 | CHECK_LE(id, message_ports_.size()); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 64 | return message_ports_[id]->object(isolate); |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 65 | }; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 66 | |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 67 | MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId( |
| 68 | Isolate* isolate, uint32_t clone_id) override { |
| 69 | CHECK_LE(clone_id, shared_array_buffers_.size()); |
| 70 | return shared_array_buffers_[clone_id]; |
| 71 | } |
| 72 | |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 73 | MaybeLocal<WasmCompiledModule> GetWasmModuleFromId( |
| 74 | Isolate* isolate, uint32_t transfer_id) override { |
| 75 | CHECK_LE(transfer_id, wasm_modules_.size()); |
| 76 | return WasmCompiledModule::FromTransferrableModule( |
| 77 | isolate, wasm_modules_[transfer_id]); |
| 78 | } |
| 79 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 80 | ValueDeserializer* deserializer = nullptr; |
| 81 | |
| 82 | private: |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 83 | const std::vector<MessagePort*>& message_ports_; |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 84 | const std::vector<Local<SharedArrayBuffer>>& shared_array_buffers_; |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 85 | const std::vector<WasmCompiledModule::TransferrableModule>& wasm_modules_; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 86 | }; |
| 87 | |
| 88 | } // anonymous namespace |
| 89 | |
| 90 | MaybeLocal<Value> Message::Deserialize(Environment* env, |
| 91 | Local<Context> context) { |
| 92 | EscapableHandleScope handle_scope(env->isolate()); |
| 93 | Context::Scope context_scope(context); |
| 94 | |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 95 | // Create all necessary MessagePort handles. |
| 96 | std::vector<MessagePort*> ports(message_ports_.size()); |
| 97 | for (uint32_t i = 0; i < message_ports_.size(); ++i) { |
| 98 | ports[i] = MessagePort::New(env, |
| 99 | context, |
| 100 | std::move(message_ports_[i])); |
| 101 | if (ports[i] == nullptr) { |
| 102 | for (MessagePort* port : ports) { |
| 103 | // This will eventually release the MessagePort object itself. |
Anna Henningsen | e1ab457 | 2018-12-16 13:34:37 | [diff] [blame] | 104 | if (port != nullptr) |
| 105 | port->Close(); |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 106 | } |
| 107 | return MaybeLocal<Value>(); |
| 108 | } |
| 109 | } |
| 110 | message_ports_.clear(); |
| 111 | |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 112 | std::vector<Local<SharedArrayBuffer>> shared_array_buffers; |
Brandon Smith | 13340d4 | 2018-10-07 01:09:29 | [diff] [blame] | 113 | // Attach all transferred SharedArrayBuffers to their new Isolate. |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 114 | for (uint32_t i = 0; i < shared_array_buffers_.size(); ++i) { |
| 115 | Local<SharedArrayBuffer> sab; |
| 116 | if (!shared_array_buffers_[i]->GetSharedArrayBuffer(env, context) |
| 117 | .ToLocal(&sab)) |
| 118 | return MaybeLocal<Value>(); |
| 119 | shared_array_buffers.push_back(sab); |
| 120 | } |
| 121 | shared_array_buffers_.clear(); |
| 122 | |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 123 | DeserializerDelegate delegate( |
| 124 | this, env, ports, shared_array_buffers, wasm_modules_); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 125 | ValueDeserializer deserializer( |
| 126 | env->isolate(), |
| 127 | reinterpret_cast<const uint8_t*>(main_message_buf_.data), |
| 128 | main_message_buf_.size, |
| 129 | &delegate); |
| 130 | delegate.deserializer = &deserializer; |
| 131 | |
Brandon Smith | 13340d4 | 2018-10-07 01:09:29 | [diff] [blame] | 132 | // Attach all transferred ArrayBuffers to their new Isolate. |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 133 | for (uint32_t i = 0; i < array_buffer_contents_.size(); ++i) { |
| 134 | Local<ArrayBuffer> ab = |
| 135 | ArrayBuffer::New(env->isolate(), |
| 136 | array_buffer_contents_[i].release(), |
| 137 | array_buffer_contents_[i].size, |
| 138 | ArrayBufferCreationMode::kInternalized); |
| 139 | deserializer.TransferArrayBuffer(i, ab); |
| 140 | } |
| 141 | array_buffer_contents_.clear(); |
| 142 | |
| 143 | if (deserializer.ReadHeader(context).IsNothing()) |
| 144 | return MaybeLocal<Value>(); |
| 145 | return handle_scope.Escape( |
| 146 | deserializer.ReadValue(context).FromMaybe(Local<Value>())); |
| 147 | } |
| 148 | |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 149 | void Message::AddSharedArrayBuffer( |
| 150 | SharedArrayBufferMetadataReference reference) { |
| 151 | shared_array_buffers_.push_back(reference); |
| 152 | } |
| 153 | |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 154 | void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) { |
| 155 | message_ports_.emplace_back(std::move(data)); |
| 156 | } |
| 157 | |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 158 | uint32_t Message::AddWASMModule(WasmCompiledModule::TransferrableModule&& mod) { |
| 159 | wasm_modules_.emplace_back(std::move(mod)); |
| 160 | return wasm_modules_.size() - 1; |
| 161 | } |
| 162 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 163 | namespace { |
| 164 | |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 165 | void ThrowDataCloneException(Environment* env, Local<String> message) { |
Timothy Gu | 5f3bdb0 | 2018-06-25 04:48:48 | [diff] [blame] | 166 | Local<Value> argv[] = { |
| 167 | message, |
| 168 | FIXED_ONE_BYTE_STRING(env->isolate(), "DataCloneError") |
| 169 | }; |
| 170 | Local<Value> exception; |
| 171 | Local<Function> domexception_ctor = env->domexception_function(); |
| 172 | CHECK(!domexception_ctor.IsEmpty()); |
| 173 | if (!domexception_ctor->NewInstance(env->context(), arraysize(argv), argv) |
| 174 | .ToLocal(&exception)) { |
| 175 | return; |
| 176 | } |
| 177 | env->isolate()->ThrowException(exception); |
| 178 | } |
| 179 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 180 | // This tells V8 how to serialize objects that it does not understand |
| 181 | // (e.g. C++ objects) into the output buffer, in a way that our own |
| 182 | // DeserializerDelegate understands how to unpack. |
| 183 | class SerializerDelegate : public ValueSerializer::Delegate { |
| 184 | public: |
| 185 | SerializerDelegate(Environment* env, Local<Context> context, Message* m) |
| 186 | : env_(env), context_(context), msg_(m) {} |
| 187 | |
| 188 | void ThrowDataCloneError(Local<String> message) override { |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 189 | ThrowDataCloneException(env_, message); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 190 | } |
| 191 | |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 192 | Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override { |
| 193 | if (env_->message_port_constructor_template()->HasInstance(object)) { |
| 194 | return WriteMessagePort(Unwrap<MessagePort>(object)); |
| 195 | } |
| 196 | |
| 197 | THROW_ERR_CANNOT_TRANSFER_OBJECT(env_); |
| 198 | return Nothing<bool>(); |
| 199 | } |
| 200 | |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 201 | Maybe<uint32_t> GetSharedArrayBufferId( |
| 202 | Isolate* isolate, |
| 203 | Local<SharedArrayBuffer> shared_array_buffer) override { |
| 204 | uint32_t i; |
| 205 | for (i = 0; i < seen_shared_array_buffers_.size(); ++i) { |
| 206 | if (seen_shared_array_buffers_[i] == shared_array_buffer) |
| 207 | return Just(i); |
| 208 | } |
| 209 | |
| 210 | auto reference = SharedArrayBufferMetadata::ForSharedArrayBuffer( |
| 211 | env_, |
| 212 | context_, |
| 213 | shared_array_buffer); |
| 214 | if (!reference) { |
| 215 | return Nothing<uint32_t>(); |
| 216 | } |
| 217 | seen_shared_array_buffers_.push_back(shared_array_buffer); |
| 218 | msg_->AddSharedArrayBuffer(reference); |
| 219 | return Just(i); |
| 220 | } |
| 221 | |
Anna Henningsen | 0a549aa | 2019-01-02 15:33:58 | [diff] [blame] | 222 | Maybe<uint32_t> GetWasmModuleTransferId( |
| 223 | Isolate* isolate, Local<WasmCompiledModule> module) override { |
| 224 | return Just(msg_->AddWASMModule(module->GetTransferrableModule())); |
| 225 | } |
| 226 | |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 227 | void Finish() { |
| 228 | // Only close the MessagePort handles and actually transfer them |
| 229 | // once we know that serialization succeeded. |
| 230 | for (MessagePort* port : ports_) { |
| 231 | port->Close(); |
| 232 | msg_->AddMessagePort(port->Detach()); |
| 233 | } |
| 234 | } |
| 235 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 236 | ValueSerializer* serializer = nullptr; |
| 237 | |
| 238 | private: |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 239 | Maybe<bool> WriteMessagePort(MessagePort* port) { |
| 240 | for (uint32_t i = 0; i < ports_.size(); i++) { |
| 241 | if (ports_[i] == port) { |
| 242 | serializer->WriteUint32(i); |
| 243 | return Just(true); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | THROW_ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST(env_); |
| 248 | return Nothing<bool>(); |
| 249 | } |
| 250 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 251 | Environment* env_; |
| 252 | Local<Context> context_; |
| 253 | Message* msg_; |
Anna Henningsen | b040404 | 2018-05-13 17:39:32 | [diff] [blame] | 254 | std::vector<Local<SharedArrayBuffer>> seen_shared_array_buffers_; |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 255 | std::vector<MessagePort*> ports_; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 256 | |
| 257 | friend class worker::Message; |
| 258 | }; |
| 259 | |
Brandon Smith | 13340d4 | 2018-10-07 01:09:29 | [diff] [blame] | 260 | } // anonymous namespace |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 261 | |
| 262 | Maybe<bool> Message::Serialize(Environment* env, |
| 263 | Local<Context> context, |
| 264 | Local<Value> input, |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 265 | Local<Value> transfer_list_v, |
| 266 | Local<Object> source_port) { |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 267 | HandleScope handle_scope(env->isolate()); |
| 268 | Context::Scope context_scope(context); |
| 269 | |
| 270 | // Verify that we're not silently overwriting an existing message. |
| 271 | CHECK(main_message_buf_.is_empty()); |
| 272 | |
| 273 | SerializerDelegate delegate(env, context, this); |
| 274 | ValueSerializer serializer(env->isolate(), &delegate); |
| 275 | delegate.serializer = &serializer; |
| 276 | |
| 277 | std::vector<Local<ArrayBuffer>> array_buffers; |
| 278 | if (transfer_list_v->IsArray()) { |
| 279 | Local<Array> transfer_list = transfer_list_v.As<Array>(); |
| 280 | uint32_t length = transfer_list->Length(); |
| 281 | for (uint32_t i = 0; i < length; ++i) { |
| 282 | Local<Value> entry; |
| 283 | if (!transfer_list->Get(context, i).ToLocal(&entry)) |
| 284 | return Nothing<bool>(); |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 285 | // Currently, we support ArrayBuffers and MessagePorts. |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 286 | if (entry->IsArrayBuffer()) { |
| 287 | Local<ArrayBuffer> ab = entry.As<ArrayBuffer>(); |
| 288 | // If we cannot render the ArrayBuffer unusable in this Isolate and |
| 289 | // take ownership of its memory, copying the buffer will have to do. |
| 290 | if (!ab->IsNeuterable() || ab->IsExternal()) |
| 291 | continue; |
Anna Henningsen | 0ff0af5 | 2019-01-30 13:57:24 | [diff] [blame] | 292 | if (std::find(array_buffers.begin(), array_buffers.end(), ab) != |
| 293 | array_buffers.end()) { |
| 294 | ThrowDataCloneException( |
| 295 | env, |
| 296 | FIXED_ONE_BYTE_STRING( |
| 297 | env->isolate(), |
| 298 | "Transfer list contains duplicate ArrayBuffer")); |
| 299 | return Nothing<bool>(); |
| 300 | } |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 301 | // We simply use the array index in the `array_buffers` list as the |
| 302 | // ID that we write into the serialized buffer. |
| 303 | uint32_t id = array_buffers.size(); |
| 304 | array_buffers.push_back(ab); |
| 305 | serializer.TransferArrayBuffer(id, ab); |
| 306 | continue; |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 307 | } else if (env->message_port_constructor_template() |
| 308 | ->HasInstance(entry)) { |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 309 | // Check if the source MessagePort is being transferred. |
| 310 | if (!source_port.IsEmpty() && entry == source_port) { |
| 311 | ThrowDataCloneException( |
| 312 | env, |
| 313 | FIXED_ONE_BYTE_STRING(env->isolate(), |
| 314 | "Transfer list contains source port")); |
| 315 | return Nothing<bool>(); |
| 316 | } |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 317 | MessagePort* port = Unwrap<MessagePort>(entry.As<Object>()); |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 318 | if (port == nullptr || port->IsDetached()) { |
| 319 | ThrowDataCloneException( |
| 320 | env, |
| 321 | FIXED_ONE_BYTE_STRING( |
| 322 | env->isolate(), |
| 323 | "MessagePort in transfer list is already detached")); |
| 324 | return Nothing<bool>(); |
| 325 | } |
Anna Henningsen | 0ff0af5 | 2019-01-30 13:57:24 | [diff] [blame] | 326 | if (std::find(delegate.ports_.begin(), delegate.ports_.end(), port) != |
| 327 | delegate.ports_.end()) { |
| 328 | ThrowDataCloneException( |
| 329 | env, |
| 330 | FIXED_ONE_BYTE_STRING( |
| 331 | env->isolate(), |
| 332 | "Transfer list contains duplicate MessagePort")); |
| 333 | return Nothing<bool>(); |
| 334 | } |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 335 | delegate.ports_.push_back(port); |
| 336 | continue; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 337 | } |
| 338 | |
| 339 | THROW_ERR_INVALID_TRANSFER_OBJECT(env); |
| 340 | return Nothing<bool>(); |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | serializer.WriteHeader(); |
| 345 | if (serializer.WriteValue(context, input).IsNothing()) { |
| 346 | return Nothing<bool>(); |
| 347 | } |
| 348 | |
| 349 | for (Local<ArrayBuffer> ab : array_buffers) { |
| 350 | // If serialization succeeded, we want to take ownership of |
| 351 | // (a.k.a. externalize) the underlying memory region and render |
| 352 | // it inaccessible in this Isolate. |
| 353 | ArrayBuffer::Contents contents = ab->Externalize(); |
| 354 | ab->Neuter(); |
| 355 | array_buffer_contents_.push_back( |
| 356 | MallocedBuffer<char> { static_cast<char*>(contents.Data()), |
| 357 | contents.ByteLength() }); |
| 358 | } |
| 359 | |
Anna Henningsen | 749a13b | 2017-10-07 21:39:02 | [diff] [blame] | 360 | delegate.Finish(); |
| 361 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 362 | // The serializer gave us a buffer allocated using `malloc()`. |
| 363 | std::pair<uint8_t*, size_t> data = serializer.Release(); |
| 364 | main_message_buf_ = |
| 365 | MallocedBuffer<char>(reinterpret_cast<char*>(data.first), data.second); |
| 366 | return Just(true); |
| 367 | } |
| 368 | |
Anna Henningsen | 57e3015 | 2018-06-10 14:40:13 | [diff] [blame] | 369 | void Message::MemoryInfo(MemoryTracker* tracker) const { |
Anna Henningsen | 57e3015 | 2018-06-10 14:40:13 | [diff] [blame] | 370 | tracker->TrackField("array_buffer_contents", array_buffer_contents_); |
| 371 | tracker->TrackFieldWithSize("shared_array_buffers", |
| 372 | shared_array_buffers_.size() * sizeof(shared_array_buffers_[0])); |
| 373 | tracker->TrackField("message_ports", message_ports_); |
| 374 | } |
| 375 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 376 | MessagePortData::MessagePortData(MessagePort* owner) : owner_(owner) { } |
| 377 | |
| 378 | MessagePortData::~MessagePortData() { |
ZYSzys | 93e0c6a | 2019-02-04 07:38:51 | [diff] [blame^] | 379 | CHECK_NULL(owner_); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 380 | Disentangle(); |
| 381 | } |
| 382 | |
Anna Henningsen | 57e3015 | 2018-06-10 14:40:13 | [diff] [blame] | 383 | void MessagePortData::MemoryInfo(MemoryTracker* tracker) const { |
| 384 | Mutex::ScopedLock lock(mutex_); |
Anna Henningsen | 57e3015 | 2018-06-10 14:40:13 | [diff] [blame] | 385 | tracker->TrackField("incoming_messages", incoming_messages_); |
| 386 | } |
| 387 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 388 | void MessagePortData::AddToIncomingQueue(Message&& message) { |
| 389 | // This function will be called by other threads. |
| 390 | Mutex::ScopedLock lock(mutex_); |
| 391 | incoming_messages_.emplace_back(std::move(message)); |
| 392 | |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 393 | if (owner_ != nullptr) { |
| 394 | Debug(owner_, "Adding message to incoming queue"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 395 | owner_->TriggerAsync(); |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 396 | } |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 397 | } |
| 398 | |
| 399 | bool MessagePortData::IsSiblingClosed() const { |
| 400 | Mutex::ScopedLock lock(*sibling_mutex_); |
| 401 | return sibling_ == nullptr; |
| 402 | } |
| 403 | |
| 404 | void MessagePortData::Entangle(MessagePortData* a, MessagePortData* b) { |
ZYSzys | 93e0c6a | 2019-02-04 07:38:51 | [diff] [blame^] | 405 | CHECK_NULL(a->sibling_); |
| 406 | CHECK_NULL(b->sibling_); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 407 | a->sibling_ = b; |
| 408 | b->sibling_ = a; |
| 409 | a->sibling_mutex_ = b->sibling_mutex_; |
| 410 | } |
| 411 | |
| 412 | void MessagePortData::PingOwnerAfterDisentanglement() { |
| 413 | Mutex::ScopedLock lock(mutex_); |
| 414 | if (owner_ != nullptr) |
| 415 | owner_->TriggerAsync(); |
| 416 | } |
| 417 | |
| 418 | void MessagePortData::Disentangle() { |
| 419 | // Grab a copy of the sibling mutex, then replace it so that each sibling |
| 420 | // has its own sibling_mutex_ now. |
| 421 | std::shared_ptr<Mutex> sibling_mutex = sibling_mutex_; |
| 422 | Mutex::ScopedLock sibling_lock(*sibling_mutex); |
| 423 | sibling_mutex_ = std::make_shared<Mutex>(); |
| 424 | |
| 425 | MessagePortData* sibling = sibling_; |
| 426 | if (sibling_ != nullptr) { |
| 427 | sibling_->sibling_ = nullptr; |
| 428 | sibling_ = nullptr; |
| 429 | } |
| 430 | |
| 431 | // We close MessagePorts after disentanglement, so we trigger the |
| 432 | // corresponding uv_async_t to let them know that this happened. |
| 433 | PingOwnerAfterDisentanglement(); |
| 434 | if (sibling != nullptr) { |
| 435 | sibling->PingOwnerAfterDisentanglement(); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | MessagePort::~MessagePort() { |
| 440 | if (data_) |
| 441 | data_->owner_ = nullptr; |
| 442 | } |
| 443 | |
| 444 | MessagePort::MessagePort(Environment* env, |
| 445 | Local<Context> context, |
| 446 | Local<Object> wrap) |
| 447 | : HandleWrap(env, |
| 448 | wrap, |
| 449 | reinterpret_cast<uv_handle_t*>(new uv_async_t()), |
| 450 | AsyncWrap::PROVIDER_MESSAGEPORT), |
| 451 | data_(new MessagePortData(this)) { |
| 452 | auto onmessage = [](uv_async_t* handle) { |
| 453 | // Called when data has been put into the queue. |
| 454 | MessagePort* channel = static_cast<MessagePort*>(handle->data); |
| 455 | channel->OnMessage(); |
| 456 | }; |
| 457 | CHECK_EQ(uv_async_init(env->event_loop(), |
| 458 | async(), |
| 459 | onmessage), 0); |
| 460 | async()->data = static_cast<void*>(this); |
| 461 | |
| 462 | Local<Value> fn; |
Anna Henningsen | 2d65e67 | 2018-09-23 17:10:54 | [diff] [blame] | 463 | if (!wrap->Get(context, env->oninit_symbol()).ToLocal(&fn)) |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 464 | return; |
| 465 | |
| 466 | if (fn->IsFunction()) { |
| 467 | Local<Function> init = fn.As<Function>(); |
| 468 | USE(init->Call(context, wrap, 0, nullptr)); |
| 469 | } |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 470 | |
| 471 | Debug(this, "Created message port"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 472 | } |
| 473 | |
| 474 | void MessagePort::AddToIncomingQueue(Message&& message) { |
| 475 | data_->AddToIncomingQueue(std::move(message)); |
| 476 | } |
| 477 | |
| 478 | uv_async_t* MessagePort::async() { |
| 479 | return reinterpret_cast<uv_async_t*>(GetHandle()); |
| 480 | } |
| 481 | |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 482 | bool MessagePort::IsDetached() const { |
| 483 | return data_ == nullptr || IsHandleClosing(); |
| 484 | } |
| 485 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 486 | void MessagePort::TriggerAsync() { |
Anna Henningsen | 22c826f | 2018-06-07 12:43:45 | [diff] [blame] | 487 | if (IsHandleClosing()) return; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 488 | CHECK_EQ(uv_async_send(async()), 0); |
| 489 | } |
| 490 | |
Anna Henningsen | 22c826f | 2018-06-07 12:43:45 | [diff] [blame] | 491 | void MessagePort::Close(v8::Local<v8::Value> close_callback) { |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 492 | Debug(this, "Closing message port, data set = %d", static_cast<int>(!!data_)); |
| 493 | |
Anna Henningsen | 22c826f | 2018-06-07 12:43:45 | [diff] [blame] | 494 | if (data_) { |
| 495 | // Wrap this call with accessing the mutex, so that TriggerAsync() |
| 496 | // can check IsHandleClosing() without race conditions. |
| 497 | Mutex::ScopedLock sibling_lock(data_->mutex_); |
| 498 | HandleWrap::Close(close_callback); |
| 499 | } else { |
| 500 | HandleWrap::Close(close_callback); |
| 501 | } |
| 502 | } |
| 503 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 504 | void MessagePort::New(const FunctionCallbackInfo<Value>& args) { |
| 505 | Environment* env = Environment::GetCurrent(args); |
| 506 | if (!args.IsConstructCall()) { |
| 507 | THROW_ERR_CONSTRUCT_CALL_REQUIRED(env); |
| 508 | return; |
| 509 | } |
| 510 | |
| 511 | Local<Context> context = args.This()->CreationContext(); |
| 512 | Context::Scope context_scope(context); |
| 513 | |
| 514 | new MessagePort(env, context, args.This()); |
| 515 | } |
| 516 | |
| 517 | MessagePort* MessagePort::New( |
| 518 | Environment* env, |
| 519 | Local<Context> context, |
| 520 | std::unique_ptr<MessagePortData> data) { |
| 521 | Context::Scope context_scope(context); |
| 522 | Local<Function> ctor; |
| 523 | if (!GetMessagePortConstructor(env, context).ToLocal(&ctor)) |
| 524 | return nullptr; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 525 | |
| 526 | // Construct a new instance, then assign the listener instance and possibly |
| 527 | // the MessagePortData to it. |
| 528 | Local<Object> instance; |
| 529 | if (!ctor->NewInstance(context).ToLocal(&instance)) |
| 530 | return nullptr; |
Anna Henningsen | d102a85 | 2018-09-23 17:26:30 | [diff] [blame] | 531 | MessagePort* port = Unwrap<MessagePort>(instance); |
| 532 | CHECK_NOT_NULL(port); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 533 | if (data) { |
| 534 | port->Detach(); |
| 535 | port->data_ = std::move(data); |
Anna Henningsen | b1cc1af | 2019-02-03 19:20:52 | [diff] [blame] | 536 | |
| 537 | // This lock is here to avoid race conditions with the `owner_` read |
| 538 | // in AddToIncomingQueue(). (This would likely be unproblematic without it, |
| 539 | // but it's better to be safe than sorry.) |
| 540 | Mutex::ScopedLock lock(port->data_->mutex_); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 541 | port->data_->owner_ = port; |
| 542 | // If the existing MessagePortData object had pending messages, this is |
| 543 | // the easiest way to run that queue. |
| 544 | port->TriggerAsync(); |
| 545 | } |
| 546 | return port; |
| 547 | } |
| 548 | |
| 549 | void MessagePort::OnMessage() { |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 550 | Debug(this, "Running MessagePort::OnMessage()"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 551 | HandleScope handle_scope(env()->isolate()); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 552 | Local<Context> context = object(env()->isolate())->CreationContext(); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 553 | |
| 554 | // data_ can only ever be modified by the owner thread, so no need to lock. |
| 555 | // However, the message port may be transferred while it is processing |
| 556 | // messages, so we need to check that this handle still owns its `data_` field |
| 557 | // on every iteration. |
| 558 | while (data_) { |
| 559 | Message received; |
| 560 | { |
| 561 | // Get the head of the message queue. |
| 562 | Mutex::ScopedLock lock(data_->mutex_); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 563 | |
| 564 | if (stop_event_loop_) { |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 565 | Debug(this, "MessagePort stops loop as requested"); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 566 | CHECK(!data_->receiving_messages_); |
| 567 | uv_stop(env()->event_loop()); |
| 568 | break; |
| 569 | } |
| 570 | |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 571 | Debug(this, "MessagePort has message, receiving = %d", |
| 572 | static_cast<int>(data_->receiving_messages_)); |
| 573 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 574 | if (!data_->receiving_messages_) |
| 575 | break; |
| 576 | if (data_->incoming_messages_.empty()) |
| 577 | break; |
| 578 | received = std::move(data_->incoming_messages_.front()); |
| 579 | data_->incoming_messages_.pop_front(); |
| 580 | } |
| 581 | |
| 582 | if (!env()->can_call_into_js()) { |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 583 | Debug(this, "MessagePort drains queue because !can_call_into_js()"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 584 | // In this case there is nothing to do but to drain the current queue. |
| 585 | continue; |
| 586 | } |
| 587 | |
| 588 | { |
| 589 | // Call the JS .onmessage() callback. |
| 590 | HandleScope handle_scope(env()->isolate()); |
| 591 | Context::Scope context_scope(context); |
| 592 | Local<Value> args[] = { |
| 593 | received.Deserialize(env(), context).FromMaybe(Local<Value>()) |
| 594 | }; |
| 595 | |
| 596 | if (args[0].IsEmpty() || |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 597 | MakeCallback(env()->onmessage_string(), 1, args).IsEmpty()) { |
| 598 | // Re-schedule OnMessage() execution in case of failure. |
| 599 | if (data_) |
| 600 | TriggerAsync(); |
| 601 | return; |
| 602 | } |
| 603 | } |
| 604 | } |
| 605 | |
| 606 | if (data_ && data_->IsSiblingClosed()) { |
| 607 | Close(); |
| 608 | } |
| 609 | } |
| 610 | |
| 611 | bool MessagePort::IsSiblingClosed() const { |
| 612 | CHECK(data_); |
| 613 | return data_->IsSiblingClosed(); |
| 614 | } |
| 615 | |
| 616 | void MessagePort::OnClose() { |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 617 | Debug(this, "MessagePort::OnClose()"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 618 | if (data_) { |
| 619 | data_->owner_ = nullptr; |
| 620 | data_->Disentangle(); |
| 621 | } |
| 622 | data_.reset(); |
| 623 | delete async(); |
| 624 | } |
| 625 | |
| 626 | std::unique_ptr<MessagePortData> MessagePort::Detach() { |
Anna Henningsen | 0ff0af5 | 2019-01-30 13:57:24 | [diff] [blame] | 627 | CHECK(data_); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 628 | Mutex::ScopedLock lock(data_->mutex_); |
| 629 | data_->owner_ = nullptr; |
| 630 | return std::move(data_); |
| 631 | } |
| 632 | |
| 633 | |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 634 | Maybe<bool> MessagePort::PostMessage(Environment* env, |
| 635 | Local<Value> message_v, |
| 636 | Local<Value> transfer_v) { |
| 637 | Isolate* isolate = env->isolate(); |
| 638 | Local<Object> obj = object(isolate); |
| 639 | Local<Context> context = obj->CreationContext(); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 640 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 641 | Message msg; |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 642 | |
| 643 | // Per spec, we need to both check if transfer list has the source port, and |
| 644 | // serialize the input message, even if the MessagePort is closed or detached. |
| 645 | |
| 646 | Maybe<bool> serialization_maybe = |
| 647 | msg.Serialize(env, context, message_v, transfer_v, obj); |
| 648 | if (data_ == nullptr) { |
| 649 | return serialization_maybe; |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 650 | } |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 651 | if (serialization_maybe.IsNothing()) { |
| 652 | return Nothing<bool>(); |
| 653 | } |
| 654 | |
| 655 | Mutex::ScopedLock lock(*data_->sibling_mutex_); |
| 656 | bool doomed = false; |
| 657 | |
| 658 | // Check if the target port is posted to itself. |
| 659 | if (data_->sibling_ != nullptr) { |
| 660 | for (const auto& port_data : msg.message_ports()) { |
| 661 | if (data_->sibling_ == port_data.get()) { |
| 662 | doomed = true; |
| 663 | ProcessEmitWarning(env, "The target port was posted to itself, and " |
| 664 | "the communication channel was lost"); |
| 665 | break; |
| 666 | } |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | if (data_->sibling_ == nullptr || doomed) |
| 671 | return Just(true); |
| 672 | |
| 673 | data_->sibling_->AddToIncomingQueue(std::move(msg)); |
| 674 | return Just(true); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 675 | } |
| 676 | |
| 677 | void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) { |
| 678 | Environment* env = Environment::GetCurrent(args); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 679 | if (args.Length() == 0) { |
| 680 | return THROW_ERR_MISSING_ARGS(env, "Not enough arguments to " |
| 681 | "MessagePort.postMessage"); |
| 682 | } |
Timothy Gu | f374d6a | 2018-06-25 03:10:37 | [diff] [blame] | 683 | |
| 684 | MessagePort* port = Unwrap<MessagePort>(args.This()); |
| 685 | // Even if the backing MessagePort object has already been deleted, we still |
| 686 | // want to serialize the message to ensure spec-compliant behavior w.r.t. |
| 687 | // transfers. |
| 688 | if (port == nullptr) { |
| 689 | Message msg; |
| 690 | Local<Object> obj = args.This(); |
| 691 | Local<Context> context = obj->CreationContext(); |
| 692 | USE(msg.Serialize(env, context, args[0], args[1], obj)); |
| 693 | return; |
| 694 | } |
| 695 | |
| 696 | port->PostMessage(env, args[0], args[1]); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 697 | } |
| 698 | |
| 699 | void MessagePort::Start() { |
| 700 | Mutex::ScopedLock lock(data_->mutex_); |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 701 | Debug(this, "Start receiving messages"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 702 | data_->receiving_messages_ = true; |
| 703 | if (!data_->incoming_messages_.empty()) |
| 704 | TriggerAsync(); |
| 705 | } |
| 706 | |
| 707 | void MessagePort::Stop() { |
| 708 | Mutex::ScopedLock lock(data_->mutex_); |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 709 | Debug(this, "Stop receiving messages"); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 710 | data_->receiving_messages_ = false; |
| 711 | } |
| 712 | |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 713 | void MessagePort::StopEventLoop() { |
| 714 | Mutex::ScopedLock lock(data_->mutex_); |
| 715 | data_->receiving_messages_ = false; |
| 716 | stop_event_loop_ = true; |
| 717 | |
Anna Henningsen | 018d618 | 2018-06-20 15:10:06 | [diff] [blame] | 718 | Debug(this, "Received StopEventLoop request"); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 719 | TriggerAsync(); |
| 720 | } |
| 721 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 722 | void MessagePort::Start(const FunctionCallbackInfo<Value>& args) { |
| 723 | Environment* env = Environment::GetCurrent(args); |
| 724 | MessagePort* port; |
| 725 | ASSIGN_OR_RETURN_UNWRAP(&port, args.This()); |
| 726 | if (!port->data_) { |
| 727 | THROW_ERR_CLOSED_MESSAGE_PORT(env); |
| 728 | return; |
| 729 | } |
| 730 | port->Start(); |
| 731 | } |
| 732 | |
| 733 | void MessagePort::Stop(const FunctionCallbackInfo<Value>& args) { |
| 734 | Environment* env = Environment::GetCurrent(args); |
| 735 | MessagePort* port; |
| 736 | ASSIGN_OR_RETURN_UNWRAP(&port, args.This()); |
| 737 | if (!port->data_) { |
| 738 | THROW_ERR_CLOSED_MESSAGE_PORT(env); |
| 739 | return; |
| 740 | } |
| 741 | port->Stop(); |
| 742 | } |
| 743 | |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 744 | void MessagePort::Drain(const FunctionCallbackInfo<Value>& args) { |
| 745 | MessagePort* port; |
| 746 | ASSIGN_OR_RETURN_UNWRAP(&port, args.This()); |
| 747 | port->OnMessage(); |
| 748 | } |
| 749 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 750 | void MessagePort::Entangle(MessagePort* a, MessagePort* b) { |
| 751 | Entangle(a, b->data_.get()); |
| 752 | } |
| 753 | |
| 754 | void MessagePort::Entangle(MessagePort* a, MessagePortData* b) { |
| 755 | MessagePortData::Entangle(a->data_.get(), b); |
| 756 | } |
| 757 | |
| 758 | MaybeLocal<Function> GetMessagePortConstructor( |
| 759 | Environment* env, Local<Context> context) { |
| 760 | // Factor generating the MessagePort JS constructor into its own piece |
| 761 | // of code, because it is needed early on in the child environment setup. |
| 762 | Local<FunctionTemplate> templ = env->message_port_constructor_template(); |
| 763 | if (!templ.IsEmpty()) |
| 764 | return templ->GetFunction(context); |
| 765 | |
| 766 | { |
| 767 | Local<FunctionTemplate> m = env->NewFunctionTemplate(MessagePort::New); |
| 768 | m->SetClassName(env->message_port_constructor_string()); |
| 769 | m->InstanceTemplate()->SetInternalFieldCount(1); |
Anna Henningsen | d527dde | 2018-09-23 17:24:33 | [diff] [blame] | 770 | m->Inherit(HandleWrap::GetConstructorTemplate(env)); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 771 | |
| 772 | env->SetProtoMethod(m, "postMessage", MessagePort::PostMessage); |
| 773 | env->SetProtoMethod(m, "start", MessagePort::Start); |
| 774 | env->SetProtoMethod(m, "stop", MessagePort::Stop); |
Anna Henningsen | 0df031a | 2017-09-01 15:03:41 | [diff] [blame] | 775 | env->SetProtoMethod(m, "drain", MessagePort::Drain); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 776 | |
| 777 | env->set_message_port_constructor_template(m); |
| 778 | } |
| 779 | |
| 780 | return GetMessagePortConstructor(env, context); |
| 781 | } |
| 782 | |
| 783 | namespace { |
| 784 | |
| 785 | static void MessageChannel(const FunctionCallbackInfo<Value>& args) { |
| 786 | Environment* env = Environment::GetCurrent(args); |
| 787 | if (!args.IsConstructCall()) { |
| 788 | THROW_ERR_CONSTRUCT_CALL_REQUIRED(env); |
| 789 | return; |
| 790 | } |
| 791 | |
| 792 | Local<Context> context = args.This()->CreationContext(); |
| 793 | Context::Scope context_scope(context); |
| 794 | |
| 795 | MessagePort* port1 = MessagePort::New(env, context); |
| 796 | MessagePort* port2 = MessagePort::New(env, context); |
| 797 | MessagePort::Entangle(port1, port2); |
| 798 | |
| 799 | args.This()->Set(env->context(), env->port1_string(), port1->object()) |
| 800 | .FromJust(); |
| 801 | args.This()->Set(env->context(), env->port2_string(), port2->object()) |
| 802 | .FromJust(); |
| 803 | } |
| 804 | |
Timothy Gu | 5f3bdb0 | 2018-06-25 04:48:48 | [diff] [blame] | 805 | static void RegisterDOMException(const FunctionCallbackInfo<Value>& args) { |
| 806 | Environment* env = Environment::GetCurrent(args); |
| 807 | CHECK_EQ(args.Length(), 1); |
| 808 | CHECK(args[0]->IsFunction()); |
| 809 | env->set_domexception_function(args[0].As<Function>()); |
| 810 | } |
| 811 | |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 812 | static void InitMessaging(Local<Object> target, |
| 813 | Local<Value> unused, |
| 814 | Local<Context> context, |
| 815 | void* priv) { |
| 816 | Environment* env = Environment::GetCurrent(context); |
| 817 | |
| 818 | { |
| 819 | Local<String> message_channel_string = |
| 820 | FIXED_ONE_BYTE_STRING(env->isolate(), "MessageChannel"); |
| 821 | Local<FunctionTemplate> templ = env->NewFunctionTemplate(MessageChannel); |
| 822 | templ->SetClassName(message_channel_string); |
| 823 | target->Set(env->context(), |
| 824 | message_channel_string, |
| 825 | templ->GetFunction(context).ToLocalChecked()).FromJust(); |
| 826 | } |
| 827 | |
| 828 | target->Set(context, |
| 829 | env->message_port_constructor_string(), |
| 830 | GetMessagePortConstructor(env, context).ToLocalChecked()) |
| 831 | .FromJust(); |
Timothy Gu | 5f3bdb0 | 2018-06-25 04:48:48 | [diff] [blame] | 832 | |
| 833 | env->SetMethod(target, "registerDOMException", RegisterDOMException); |
Anna Henningsen | e7a2367 | 2017-09-05 20:38:32 | [diff] [blame] | 834 | } |
| 835 | |
| 836 | } // anonymous namespace |
| 837 | |
| 838 | } // namespace worker |
| 839 | } // namespace node |
| 840 | |
| 841 | NODE_MODULE_CONTEXT_AWARE_INTERNAL(messaging, node::worker::InitMessaging) |