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.h Lines: 7 19 36.8 %
Date: 2020-08-07 22:13:19 Branches: 0 0 - %

Line Branch Exec Source
1
#ifndef SRC_NODE_MESSAGING_H_
2
#define SRC_NODE_MESSAGING_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "env.h"
7
#include "node_mutex.h"
8
#include <list>
9
10
namespace node {
11
namespace worker {
12
13
class MessagePortData;
14
class MessagePort;
15
16
typedef MaybeStackBuffer<v8::Local<v8::Value>, 8> TransferList;
17
18
// Used to represent the in-flight structure of an object that is being
19
// transfered or cloned using postMessage().
20
66147
class TransferData : public MemoryRetainer {
21
 public:
22
  // Deserialize this object on the receiving end after a .postMessage() call.
23
  // - `context` may not be the same as `env->context()`. This method should
24
  //    not produce JS objects coming from Contexts other than `context`.
25
  // - `self` is a unique_ptr for the object that this is being called on.
26
  // - The return value is treated like a `Maybe`, i.e. if `nullptr` is
27
  //   returned, any further deserialization of the message is stopped and
28
  //   control is returned to the event loop or JS as soon as possible.
29
  virtual BaseObjectPtr<BaseObject> Deserialize(
30
      Environment* env,
31
      v8::Local<v8::Context> context,
32
      std::unique_ptr<TransferData> self) = 0;
33
  // FinalizeTransferWrite() is the counterpart to
34
  // BaseObject::FinalizeTransferRead(). It is called right after the transfer
35
  // data was created, and defaults to doing nothing. After this function,
36
  // this object should not hold any more Isolate-specific data.
37
  virtual v8::Maybe<bool> FinalizeTransferWrite(
38
      v8::Local<v8::Context> context, v8::ValueSerializer* serializer);
39
};
40
41
// Represents a single communication message.
42
343157
class Message : public MemoryRetainer {
43
 public:
44
  // Create a Message with a specific underlying payload, in the format of the
45
  // V8 ValueSerializer API. If `payload` is empty, this message indicates
46
  // that the receiving message port should close itself.
47
  explicit Message(MallocedBuffer<char>&& payload = MallocedBuffer<char>());
48
49
108892
  Message(Message&& other) = default;
50
  Message& operator=(Message&& other) = default;
51
  Message& operator=(const Message&) = delete;
52
  Message(const Message&) = delete;
53
54
  // Whether this is a message indicating that the port is to be closed.
55
  // This is the last message to be received by a MessagePort.
56
  bool IsCloseMessage() const;
57
58
  // Deserialize the contained JS value. May only be called once, and only
59
  // after Serialize() has been called (e.g. by another thread).
60
  v8::MaybeLocal<v8::Value> Deserialize(Environment* env,
61
                                        v8::Local<v8::Context> context);
62
63
  // Serialize a JS value, and optionally transfer objects, into this message.
64
  // The Message object retains ownership of all transferred objects until
65
  // deserialization.
66
  // The source_port parameter, if provided, will make Serialize() throw a
67
  // "DataCloneError" DOMException if source_port is found in transfer_list.
68
  v8::Maybe<bool> Serialize(Environment* env,
69
                            v8::Local<v8::Context> context,
70
                            v8::Local<v8::Value> input,
71
                            const TransferList& transfer_list,
72
                            v8::Local<v8::Object> source_port =
73
                                v8::Local<v8::Object>());
74
75
  // Internal method of Message that is called when a new SharedArrayBuffer
76
  // object is encountered in the incoming value's structure.
77
  void AddSharedArrayBuffer(std::shared_ptr<v8::BackingStore> backing_store);
78
  // Internal method of Message that is called once serialization finishes
79
  // and that transfers ownership of `data` to this message.
80
  void AddTransferable(std::unique_ptr<TransferData>&& data);
81
  // Internal method of Message that is called when a new WebAssembly.Module
82
  // object is encountered in the incoming value's structure.
83
  uint32_t AddWASMModule(v8::CompiledWasmModule&& mod);
84
85
  // The host objects that will be transferred, as recorded by Serialize()
86
  // (e.g. MessagePorts).
87
  // Used for warning user about posting the target MessagePort to itself,
88
  // which will as a side effect destroy the communication channel.
89
42780
  const std::vector<std::unique_ptr<TransferData>>& transferables() const {
90
42780
    return transferables_;
91
  }
92
93
  void MemoryInfo(MemoryTracker* tracker) const override;
94
95
  SET_MEMORY_INFO_NAME(Message)
96
  SET_SELF_SIZE(Message)
97
98
 private:
99
  MallocedBuffer<char> main_message_buf_;
100
  std::vector<std::shared_ptr<v8::BackingStore>> array_buffers_;
101
  std::vector<std::shared_ptr<v8::BackingStore>> shared_array_buffers_;
102
  std::vector<std::unique_ptr<TransferData>> transferables_;
103
  std::vector<v8::CompiledWasmModule> wasm_modules_;
104
105
  friend class MessagePort;
106
};
107
108
// This contains all data for a `MessagePort` instance that is not tied to
109
// a specific Environment/Isolate/event loop, for easier transfer between those.
110
class MessagePortData : public TransferData {
111
 public:
112
  explicit MessagePortData(MessagePort* owner);
113
  ~MessagePortData() override;
114
115
  MessagePortData(MessagePortData&& other) = delete;
116
  MessagePortData& operator=(MessagePortData&& other) = delete;
117
  MessagePortData(const MessagePortData& other) = delete;
118
  MessagePortData& operator=(const MessagePortData& other) = delete;
119
120
  // Add a message to the incoming queue and notify the receiver.
121
  // This may be called from any thread.
122
  void AddToIncomingQueue(Message&& message);
123
124
  // Turns `a` and `b` into siblings, i.e. connects the sending side of one
125
  // to the receiving side of the other. This is not thread-safe.
126
  static void Entangle(MessagePortData* a, MessagePortData* b);
127
128
  // Removes any possible sibling. This is thread-safe (it acquires both
129
  // `sibling_mutex_` and `mutex_`), and has to be because it is called once
130
  // the corresponding JS handle handle wants to close
131
  // which can happen on either side of a worker.
132
  void Disentangle();
133
134
  void MemoryInfo(MemoryTracker* tracker) const override;
135
  BaseObjectPtr<BaseObject> Deserialize(
136
      Environment* env,
137
      v8::Local<v8::Context> context,
138
      std::unique_ptr<TransferData> self) override;
139
140
  SET_MEMORY_INFO_NAME(MessagePortData)
141
  SET_SELF_SIZE(MessagePortData)
142
143
 private:
144
  // This mutex protects all fields below it, with the exception of
145
  // sibling_.
146
  mutable Mutex mutex_;
147
  std::list<Message> incoming_messages_;
148
  MessagePort* owner_ = nullptr;
149
  // This mutex protects the sibling_ field and is shared between two entangled
150
  // MessagePorts. If both mutexes are acquired, this one needs to be
151
  // acquired first.
152
  std::shared_ptr<Mutex> sibling_mutex_ = std::make_shared<Mutex>();
153
  MessagePortData* sibling_ = nullptr;
154
155
  friend class MessagePort;
156
};
157
158
// A message port that receives messages from other threads, including
159
// the uv_async_t handle that is used to notify the current event loop of
160
// new incoming messages.
161
class MessagePort : public HandleWrap {
162
 private:
163
  // Create a new MessagePort. The `context` argument specifies the Context
164
  // instance that is used for creating the values emitted from this port.
165
  // This is called by MessagePort::New(), which is the public API used for
166
  // creating MessagePort instances.
167
  MessagePort(Environment* env,
168
              v8::Local<v8::Context> context,
169
              v8::Local<v8::Object> wrap);
170
171
 public:
172
  ~MessagePort() override;
173
174
  // Create a new message port instance, optionally over an existing
175
  // `MessagePortData` object.
176
  static MessagePort* New(Environment* env,
177
                          v8::Local<v8::Context> context,
178
                          std::unique_ptr<MessagePortData> data = nullptr);
179
180
  // Send a message, i.e. deliver it into the sibling's incoming queue.
181
  // If this port is closed, or if there is no sibling, this message is
182
  // serialized with transfers, then silently discarded.
183
  v8::Maybe<bool> PostMessage(Environment* env,
184
                              v8::Local<v8::Value> message,
185
                              const TransferList& transfer);
186
187
  // Start processing messages on this port as a receiving end.
188
  void Start();
189
  // Stop processing messages on this port as a receiving end.
190
  void Stop();
191
192
  /* constructor */
193
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
194
  /* prototype methods */
195
  static void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
196
  static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
197
  static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
198
  static void Drain(const v8::FunctionCallbackInfo<v8::Value>& args);
199
  static void ReceiveMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
200
201
  /* static */
202
  static void MoveToContext(const v8::FunctionCallbackInfo<v8::Value>& args);
203
204
  // Turns `a` and `b` into siblings, i.e. connects the sending side of one
205
  // to the receiving side of the other. This is not thread-safe.
206
  static void Entangle(MessagePort* a, MessagePort* b);
207
  static void Entangle(MessagePort* a, MessagePortData* b);
208
209
  // Detach this port's data for transferring. After this, the MessagePortData
210
  // is no longer associated with this handle, although it can still receive
211
  // messages.
212
  std::unique_ptr<MessagePortData> Detach();
213
214
  void Close(
215
      v8::Local<v8::Value> close_callback = v8::Local<v8::Value>()) override;
216
217
  // Returns true if either data_ has been freed, or if the handle is being
218
  // closed. Equivalent to the [[Detached]] internal slot in the HTML Standard.
219
  //
220
  // If checking if a JavaScript MessagePort object is detached, this method
221
  // alone is often not enough, since the backing C++ MessagePort object may
222
  // have been deleted already. For all intents and purposes, an object with a
223
  // NULL pointer to the C++ MessagePort object is also detached.
224
  inline bool IsDetached() const;
225
226
  TransferMode GetTransferMode() const override;
227
  std::unique_ptr<TransferData> TransferForMessaging() override;
228
229
  void MemoryInfo(MemoryTracker* tracker) const override;
230
  SET_MEMORY_INFO_NAME(MessagePort)
231
  SET_SELF_SIZE(MessagePort)
232
233
 private:
234
  void OnClose() override;
235
  void OnMessage();
236
  void TriggerAsync();
237
  v8::MaybeLocal<v8::Value> ReceiveMessage(v8::Local<v8::Context> context,
238
                                           bool only_if_receiving);
239
240
  std::unique_ptr<MessagePortData> data_ = nullptr;
241
  bool receiving_messages_ = false;
242
  uv_async_t async_;
243
  v8::Global<v8::Function> emit_message_fn_;
244
245
  friend class MessagePortData;
246
};
247
248
// Provide a base class from which JS classes that should be transferable or
249
// cloneable by postMesssage() can inherit.
250
// See e.g. FileHandle in internal/fs/promises.js for an example.
251
584
class JSTransferable : public BaseObject {
252
 public:
253
  JSTransferable(Environment* env, v8::Local<v8::Object> obj);
254
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
255
256
  TransferMode GetTransferMode() const override;
257
  std::unique_ptr<TransferData> TransferForMessaging() override;
258
  std::unique_ptr<TransferData> CloneForMessaging() const override;
259
  v8::Maybe<std::vector<BaseObjectPtr<BaseObject>>>
260
      NestedTransferables() const override;
261
  v8::Maybe<bool> FinalizeTransferRead(
262
      v8::Local<v8::Context> context,
263
      v8::ValueDeserializer* deserializer) override;
264
265
  SET_NO_MEMORY_INFO()
266
  SET_MEMORY_INFO_NAME(JSTransferable)
267
  SET_SELF_SIZE(JSTransferable)
268
269
 private:
270
  std::unique_ptr<TransferData> TransferOrClone(TransferMode mode) const;
271
272
15
  class Data : public TransferData {
273
   public:
274
    Data(std::string&& deserialize_info, v8::Global<v8::Value>&& data);
275
276
    BaseObjectPtr<BaseObject> Deserialize(
277
        Environment* env,
278
        v8::Local<v8::Context> context,
279
        std::unique_ptr<TransferData> self) override;
280
    v8::Maybe<bool> FinalizeTransferWrite(
281
        v8::Local<v8::Context> context,
282
        v8::ValueSerializer* serializer) override;
283
284
    SET_NO_MEMORY_INFO()
285
    SET_MEMORY_INFO_NAME(JSTransferableTransferData)
286
    SET_SELF_SIZE(Data)
287
288
   private:
289
    std::string deserialize_info_;
290
    v8::Global<v8::Value> data_;
291
  };
292
};
293
294
v8::Local<v8::FunctionTemplate> GetMessagePortConstructorTemplate(
295
    Environment* env);
296
297
}  // namespace worker
298
}  // namespace node
299
300
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
301
302
303
#endif  // SRC_NODE_MESSAGING_H_