GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/inspector/main_thread_interface.cc Lines: 165 166 99.4 %
Date: 2020-08-07 22:13:19 Branches: 28 42 66.7 %

Line Branch Exec Source
1
#include "main_thread_interface.h"
2
3
#include "env-inl.h"
4
#include "node_mutex.h"
5
#include "v8-inspector.h"
6
#include "util-inl.h"
7
8
#include <unicode/unistr.h>
9
10
#include <functional>
11
#include <memory>
12
13
namespace node {
14
namespace inspector {
15
namespace {
16
17
using v8_inspector::StringBuffer;
18
using v8_inspector::StringView;
19
20
template <typename T>
21
class DeletableWrapper : public Deletable {
22
 public:
23
47
  explicit DeletableWrapper(std::unique_ptr<T> object)
24
47
                        : object_(std::move(object)) {}
25
94
  ~DeletableWrapper() override = default;
26
27
523
  static T* get(MainThreadInterface* thread, int id) {
28
    return
29
523
        static_cast<DeletableWrapper<T>*>(thread->GetObject(id))->object_.get();
30
  }
31
32
 private:
33
  std::unique_ptr<T> object_;
34
};
35
36
template <typename T>
37
47
std::unique_ptr<Deletable> WrapInDeletable(std::unique_ptr<T> object) {
38
  return std::unique_ptr<DeletableWrapper<T>>(
39
47
      new DeletableWrapper<T>(std::move(object)));
40
}
41
42
template <typename Factory>
43
64
class CreateObjectRequest : public Request {
44
 public:
45
32
  CreateObjectRequest(int object_id, Factory factory)
46
32
                      : object_id_(object_id), factory_(std::move(factory)) {}
47
48
32
  void Call(MainThreadInterface* thread) override {
49
32
    thread->AddObject(object_id_, WrapInDeletable(factory_(thread)));
50
32
  }
51
52
 private:
53
  int object_id_;
54
  Factory factory_;
55
};
56
57
template <typename Factory>
58
32
std::unique_ptr<Request> NewCreateRequest(int object_id, Factory factory) {
59
  return std::unique_ptr<Request>(
60
32
      new CreateObjectRequest<Factory>(object_id, std::move(factory)));
61
}
62
63
94
class DeleteRequest : public Request {
64
 public:
65
47
  explicit DeleteRequest(int object_id) : object_id_(object_id) {}
66
67
34
  void Call(MainThreadInterface* thread) override {
68
34
    thread->RemoveObject(object_id_);
69
34
  }
70
71
 private:
72
  int object_id_;
73
};
74
75
template <typename Target, typename Fn>
76
1046
class CallRequest : public Request {
77
 public:
78
523
  CallRequest(int id, Fn fn) : id_(id), fn_(std::move(fn)) {}
79
80
523
  void Call(MainThreadInterface* thread) override {
81
523
    fn_(DeletableWrapper<Target>::get(thread, id_));
82
523
  }
83
84
 private:
85
  int id_;
86
  Fn fn_;
87
};
88
89
template <typename T>
90
class AnotherThreadObjectReference {
91
 public:
92
47
  AnotherThreadObjectReference(
93
      std::shared_ptr<MainThreadHandle> thread, int object_id)
94
47
      : thread_(thread), object_id_(object_id) {}
95
96
  template <typename Factory>
97
32
  AnotherThreadObjectReference(
98
      std::shared_ptr<MainThreadHandle> thread, Factory factory)
99
32
      : AnotherThreadObjectReference(thread, thread->newObjectId()) {
100
32
    thread_->Post(NewCreateRequest(object_id_, std::move(factory)));
101
32
  }
102
  AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete;
103
104
47
  ~AnotherThreadObjectReference() {
105
    // Disappearing thread may cause a memory leak
106
47
    thread_->Post(std::make_unique<DeleteRequest>(object_id_));
107
47
  }
108
109
  template <typename Fn>
110
523
  void Call(Fn fn) const {
111
    using Request = CallRequest<T, Fn>;
112
1046
    thread_->Post(std::unique_ptr<Request>(
113
1046
        new Request(object_id_, std::move(fn))));
114
523
  }
115
116
  template <typename Arg>
117
186
  void Call(void (T::*fn)(Arg), Arg argument) const {
118
186
    Call(std::bind(Apply<Arg>, std::placeholders::_1, fn, std::move(argument)));
119
186
  }
120
121
 private:
122
  // This has to use non-const reference to support std::bind with non-copyable
123
  // types
124
  template <typename Argument>
125
186
  static void Apply(T* target, void (T::*fn)(Argument),
126
    /* NOLINT (runtime/references) */ Argument& argument) {
127

186
    (target->*fn)(std::move(argument));
128
186
  }
129
130
  std::shared_ptr<MainThreadHandle> thread_;
131
  const int object_id_;
132
};
133
134
32
class MainThreadSessionState {
135
 public:
136
32
  MainThreadSessionState(MainThreadInterface* thread, bool prevent_shutdown)
137
32
                         : thread_(thread),
138
32
                           prevent_shutdown_(prevent_shutdown) {}
139
140
32
  static std::unique_ptr<MainThreadSessionState> Create(
141
      MainThreadInterface* thread, bool prevent_shutdown) {
142
32
    return std::make_unique<MainThreadSessionState>(thread, prevent_shutdown);
143
  }
144
145
32
  void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) {
146
32
    Agent* agent = thread_->inspector_agent();
147
32
    if (agent != nullptr)
148
32
      session_ = agent->Connect(std::move(delegate), prevent_shutdown_);
149
32
  }
150
151
154
  void Dispatch(std::unique_ptr<StringBuffer> message) {
152
154
    session_->Dispatch(message->string());
153
154
  }
154
155
 private:
156
  MainThreadInterface* thread_;
157
  bool prevent_shutdown_;
158
  std::unique_ptr<InspectorSession> session_;
159
};
160
161
64
class CrossThreadInspectorSession : public InspectorSession {
162
 public:
163
32
  CrossThreadInspectorSession(
164
      int id,
165
      std::shared_ptr<MainThreadHandle> thread,
166
      std::unique_ptr<InspectorSessionDelegate> delegate,
167
      bool prevent_shutdown)
168
96
      : state_(thread, std::bind(MainThreadSessionState::Create,
169
                                 std::placeholders::_1,
170
64
                                 prevent_shutdown)) {
171
32
    state_.Call(&MainThreadSessionState::Connect, std::move(delegate));
172
32
  }
173
174
154
  void Dispatch(const StringView& message) override {
175
154
    state_.Call(&MainThreadSessionState::Dispatch,
176
308
                StringBuffer::create(message));
177
154
  }
178
179
 private:
180
  AnotherThreadObjectReference<MainThreadSessionState> state_;
181
};
182
183
30
class ThreadSafeDelegate : public InspectorSessionDelegate {
184
 public:
185
15
  ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread, int object_id)
186
15
                     : thread_(thread), delegate_(thread, object_id) {}
187
188
337
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
189
674
    delegate_.Call(
190
1685
        [m = StringBuffer::create(message)]
191
337
        (InspectorSessionDelegate* delegate) {
192
337
      delegate->SendMessageToFrontend(m->string());
193
674
    });
194
337
  }
195
196
 private:
197
  std::shared_ptr<MainThreadHandle> thread_;
198
  AnotherThreadObjectReference<InspectorSessionDelegate> delegate_;
199
};
200
}  // namespace
201
202
203
4754
MainThreadInterface::MainThreadInterface(Agent* agent) : agent_(agent) {}
204
205
8575
MainThreadInterface::~MainThreadInterface() {
206
4287
  if (handle_)
207
4289
    handle_->Reset();
208
4289
}
209
210
6873
void MainThreadInterface::Post(std::unique_ptr<Request> request) {
211
6873
  CHECK_NOT_NULL(agent_);
212
13746
  Mutex::ScopedLock scoped_lock(requests_lock_);
213
6873
  bool needs_notify = requests_.empty();
214
6873
  requests_.push_back(std::move(request));
215
6873
  if (needs_notify) {
216
13050
    std::weak_ptr<MainThreadInterface> weak_self {shared_from_this()};
217
39141
    agent_->env()->RequestInterrupt([weak_self](Environment*) {
218
6521
      if (auto iface = weak_self.lock()) iface->DispatchMessages();
219
13045
    });
220
  }
221
6873
  incoming_message_cond_.Broadcast(scoped_lock);
222
6873
}
223
224
134
bool MainThreadInterface::WaitForFrontendEvent() {
225
  // We allow DispatchMessages reentry as we enter the pause. This is important
226
  // to support debugging the code invoked by an inspector call, such
227
  // as Runtime.evaluate
228
134
  dispatching_messages_ = false;
229
134
  if (dispatching_message_queue_.empty()) {
230
268
    Mutex::ScopedLock scoped_lock(requests_lock_);
231
268
    while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
232
  }
233
134
  return true;
234
}
235
236
6521
void MainThreadInterface::DispatchMessages() {
237
6521
  if (dispatching_messages_)
238
17
    return;
239
6504
  dispatching_messages_ = true;
240
6504
  bool had_messages = false;
241
13025
  do {
242
13025
    if (dispatching_message_queue_.empty()) {
243
26050
      Mutex::ScopedLock scoped_lock(requests_lock_);
244
13025
      requests_.swap(dispatching_message_queue_);
245
    }
246
13025
    had_messages = !dispatching_message_queue_.empty();
247
26727
    while (!dispatching_message_queue_.empty()) {
248
13702
      MessageQueue::value_type task;
249
6851
      std::swap(dispatching_message_queue_.front(), task);
250
6851
      dispatching_message_queue_.pop_front();
251
252
13702
      v8::SealHandleScope seal_handle_scope(agent_->env()->isolate());
253
6851
      task->Call(this);
254
    }
255
  } while (had_messages);
256
6504
  dispatching_messages_ = false;
257
}
258
259
9914
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
260
9914
  if (handle_ == nullptr)
261
4754
    handle_ = std::make_shared<MainThreadHandle>(this);
262
9915
  return handle_;
263
}
264
265
5130
void MainThreadInterface::AddObject(int id,
266
                                    std::unique_ptr<Deletable> object) {
267
5130
  CHECK_NOT_NULL(object);
268
5130
  managed_objects_[id] = std::move(object);
269
5130
}
270
271
322
void MainThreadInterface::RemoveObject(int id) {
272
322
  CHECK_EQ(1, managed_objects_.erase(id));
273
322
}
274
275
523
Deletable* MainThreadInterface::GetObject(int id) {
276
523
  Deletable* pointer = GetObjectIfExists(id);
277
  // This would mean the object is requested after it was disposed, which is
278
  // a coding error.
279
523
  CHECK_NOT_NULL(pointer);
280
523
  return pointer;
281
}
282
283
527
Deletable* MainThreadInterface::GetObjectIfExists(int id) {
284
527
  auto iterator = managed_objects_.find(id);
285
527
  if (iterator == managed_objects_.end()) {
286
    return nullptr;
287
  }
288
527
  return iterator->second.get();
289
}
290
291
57487
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
292
  icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
293
114978
      icu::StringPiece(message.data(), message.length()));
294
57492
  StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
295
114982
                  utf16.length());
296
114979
  return StringBuffer::create(view);
297
}
298
299
32
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
300
    std::unique_ptr<InspectorSessionDelegate> delegate,
301
    bool prevent_shutdown) {
302
  return std::unique_ptr<InspectorSession>(
303
32
      new CrossThreadInspectorSession(++next_session_id_,
304
64
                                      shared_from_this(),
305
32
                                      std::move(delegate),
306
96
                                      prevent_shutdown));
307
}
308
309
11214
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
310
22429
  Mutex::ScopedLock scoped_lock(block_lock_);
311
11215
  if (!main_thread_)
312
4342
    return false;
313
6873
  main_thread_->Post(std::move(request));
314
6873
  return true;
315
}
316
317
4287
void MainThreadHandle::Reset() {
318
8576
  Mutex::ScopedLock scoped_lock(block_lock_);
319
4289
  main_thread_ = nullptr;
320
4289
}
321
322
std::unique_ptr<InspectorSessionDelegate>
323
15
MainThreadHandle::MakeDelegateThreadSafe(
324
    std::unique_ptr<InspectorSessionDelegate> delegate) {
325
15
  int id = newObjectId();
326
15
  main_thread_->AddObject(id, WrapInDeletable(std::move(delegate)));
327
  return std::unique_ptr<InspectorSessionDelegate>(
328
15
      new ThreadSafeDelegate(shared_from_this(), id));
329
}
330
331
346
bool MainThreadHandle::Expired() {
332
692
  Mutex::ScopedLock scoped_lock(block_lock_);
333
692
  return main_thread_ == nullptr;
334
}
335
}  // namespace inspector
336

13323
}  // namespace node