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: 168 169 99.4 %
Date: 2019-10-07 22:40:39 Branches: 36 58 62.1 %

Line Branch Exec Source
1
#include "main_thread_interface.h"
2
3
#include "node_mutex.h"
4
#include "v8-inspector.h"
5
#include "util-inl.h"
6
7
#include <unicode/unistr.h>
8
9
#include <functional>
10
#include <memory>
11
12
namespace node {
13
namespace inspector {
14
namespace {
15
16
using v8_inspector::StringView;
17
using v8_inspector::StringBuffer;
18
19
template <typename T>
20
class DeletableWrapper : public Deletable {
21
 public:
22
45
  explicit DeletableWrapper(std::unique_ptr<T> object)
23
45
                        : object_(std::move(object)) {}
24

90
  ~DeletableWrapper() override = default;
25
26
440
  static T* get(MainThreadInterface* thread, int id) {
27
    return
28
440
        static_cast<DeletableWrapper<T>*>(thread->GetObject(id))->object_.get();
29
  }
30
31
 private:
32
  std::unique_ptr<T> object_;
33
};
34
35
template <typename T>
36
45
std::unique_ptr<Deletable> WrapInDeletable(std::unique_ptr<T> object) {
37
  return std::unique_ptr<DeletableWrapper<T>>(
38
45
      new DeletableWrapper<T>(std::move(object)));
39
}
40
41
template <typename Factory>
42
62
class CreateObjectRequest : public Request {
43
 public:
44
31
  CreateObjectRequest(int object_id, Factory factory)
45
31
                      : object_id_(object_id), factory_(std::move(factory)) {}
46
47
31
  void Call(MainThreadInterface* thread) override {
48
31
    thread->AddObject(object_id_, WrapInDeletable(factory_(thread)));
49
31
  }
50
51
 private:
52
  int object_id_;
53
  Factory factory_;
54
};
55
56
template <typename Factory>
57
31
std::unique_ptr<Request> NewCreateRequest(int object_id, Factory factory) {
58
  return std::unique_ptr<Request>(
59
31
      new CreateObjectRequest<Factory>(object_id, std::move(factory)));
60
}
61
62
90
class DeleteRequest : public Request {
63
 public:
64
45
  explicit DeleteRequest(int object_id) : object_id_(object_id) {}
65
66
33
  void Call(MainThreadInterface* thread) override {
67
33
    thread->RemoveObject(object_id_);
68
33
  }
69
70
 private:
71
  int object_id_;
72
};
73
74
template <typename Target, typename Fn>
75

880
class CallRequest : public Request {
76
 public:
77
440
  CallRequest(int id, Fn fn) : id_(id), fn_(std::move(fn)) {}
78
79
440
  void Call(MainThreadInterface* thread) override {
80
440
    fn_(DeletableWrapper<Target>::get(thread, id_));
81
440
  }
82
83
 private:
84
  int id_;
85
  Fn fn_;
86
};
87
88
11909
class DispatchMessagesTask : public v8::Task {
89
 public:
90
6251
  explicit DispatchMessagesTask(MainThreadInterface* thread)
91
6251
                                : thread_(thread) {}
92
93
5956
  void Run() override {
94
5956
    thread_->DispatchMessages();
95
5956
  }
96
97
 private:
98
  MainThreadInterface* thread_;
99
};
100
101
template <typename T>
102
class AnotherThreadObjectReference {
103
 public:
104
45
  AnotherThreadObjectReference(
105
      std::shared_ptr<MainThreadHandle> thread, int object_id)
106
45
      : thread_(thread), object_id_(object_id) {}
107
108
  template <typename Factory>
109
31
  AnotherThreadObjectReference(
110
      std::shared_ptr<MainThreadHandle> thread, Factory factory)
111
31
      : AnotherThreadObjectReference(thread, thread->newObjectId()) {
112
31
    thread_->Post(NewCreateRequest(object_id_, std::move(factory)));
113
31
  }
114
  AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete;
115
116
45
  ~AnotherThreadObjectReference() {
117
    // Disappearing thread may cause a memory leak
118
45
    thread_->Post(std::make_unique<DeleteRequest>(object_id_));
119
45
  }
120
121
  template <typename Fn>
122
440
  void Call(Fn fn) const {
123
    using Request = CallRequest<T, Fn>;
124
440
    thread_->Post(std::unique_ptr<Request>(
125
440
        new Request(object_id_, std::move(fn))));
126
440
  }
127
128
  template <typename Arg>
129
173
  void Call(void (T::*fn)(Arg), Arg argument) const {
130
173
    Call(std::bind(Apply<Arg>, std::placeholders::_1, fn, std::move(argument)));
131
173
  }
132
133
 private:
134
  // This has to use non-const reference to support std::bind with non-copyable
135
  // types
136
  template <typename Argument>
137
173
  static void Apply(T* target, void (T::*fn)(Argument),
138
    /* NOLINT (runtime/references) */ Argument& argument) {
139

173
    (target->*fn)(std::move(argument));
140
173
  }
141
142
  std::shared_ptr<MainThreadHandle> thread_;
143
  const int object_id_;
144
};
145
146
31
class MainThreadSessionState {
147
 public:
148
31
  MainThreadSessionState(MainThreadInterface* thread, bool prevent_shutdown)
149
                         : thread_(thread),
150
31
                           prevent_shutdown_(prevent_shutdown) {}
151
152
31
  static std::unique_ptr<MainThreadSessionState> Create(
153
      MainThreadInterface* thread, bool prevent_shutdown) {
154
31
    return std::make_unique<MainThreadSessionState>(thread, prevent_shutdown);
155
  }
156
157
31
  void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) {
158
31
    Agent* agent = thread_->inspector_agent();
159
31
    if (agent != nullptr)
160
31
      session_ = agent->Connect(std::move(delegate), prevent_shutdown_);
161
31
  }
162
163
142
  void Dispatch(std::unique_ptr<StringBuffer> message) {
164
142
    session_->Dispatch(message->string());
165
142
  }
166
167
 private:
168
  MainThreadInterface* thread_;
169
  bool prevent_shutdown_;
170
  std::unique_ptr<InspectorSession> session_;
171
};
172
173
62
class CrossThreadInspectorSession : public InspectorSession {
174
 public:
175
31
  CrossThreadInspectorSession(
176
      int id,
177
      std::shared_ptr<MainThreadHandle> thread,
178
      std::unique_ptr<InspectorSessionDelegate> delegate,
179
      bool prevent_shutdown)
180
      : state_(thread, std::bind(MainThreadSessionState::Create,
181
                                 std::placeholders::_1,
182
31
                                 prevent_shutdown)) {
183
31
    state_.Call(&MainThreadSessionState::Connect, std::move(delegate));
184
31
  }
185
186
142
  void Dispatch(const StringView& message) override {
187
    state_.Call(&MainThreadSessionState::Dispatch,
188
142
                StringBuffer::create(message));
189
142
  }
190
191
 private:
192
  AnotherThreadObjectReference<MainThreadSessionState> state_;
193
};
194
195
28
class ThreadSafeDelegate : public InspectorSessionDelegate {
196
 public:
197
14
  ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread, int object_id)
198
14
                     : thread_(thread), delegate_(thread, object_id) {}
199
200
267
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
201
    delegate_.Call(
202
1335
        [m = StringBuffer::create(message)]
203
267
        (InspectorSessionDelegate* delegate) {
204
267
      delegate->SendMessageToFrontend(m->string());
205
534
    });
206
267
  }
207
208
 private:
209
  std::shared_ptr<MainThreadHandle> thread_;
210
  AnotherThreadObjectReference<InspectorSessionDelegate> delegate_;
211
};
212
}  // namespace
213
214
215
5098
MainThreadInterface::MainThreadInterface(Agent* agent, uv_loop_t* loop,
216
                                         v8::Isolate* isolate,
217
                                         v8::Platform* platform)
218
                                         : agent_(agent), isolate_(isolate),
219
5098
                                           platform_(platform) {
220
5099
}
221
222
9324
MainThreadInterface::~MainThreadInterface() {
223
4662
  if (handle_)
224
4662
    handle_->Reset();
225
4662
}
226
227
6507
void MainThreadInterface::Post(std::unique_ptr<Request> request) {
228
6507
  Mutex::ScopedLock scoped_lock(requests_lock_);
229
6507
  bool needs_notify = requests_.empty();
230
6507
  requests_.push_back(std::move(request));
231
6507
  if (needs_notify) {
232

6251
    if (isolate_ != nullptr && platform_ != nullptr) {
233
      std::shared_ptr<v8::TaskRunner> taskrunner =
234
6251
        platform_->GetForegroundTaskRunner(isolate_);
235
6251
      taskrunner->PostTask(std::make_unique<DispatchMessagesTask>(this));
236
18669
      isolate_->RequestInterrupt([](v8::Isolate* isolate, void* thread) {
237
6209
        static_cast<MainThreadInterface*>(thread)->DispatchMessages();
238
24920
      }, this);
239
    }
240
  }
241
6507
  incoming_message_cond_.Broadcast(scoped_lock);
242
6507
}
243
244
130
bool MainThreadInterface::WaitForFrontendEvent() {
245
  // We allow DispatchMessages reentry as we enter the pause. This is important
246
  // to support debugging the code invoked by an inspector call, such
247
  // as Runtime.evaluate
248
130
  dispatching_messages_ = false;
249
130
  if (dispatching_message_queue_.empty()) {
250
130
    Mutex::ScopedLock scoped_lock(requests_lock_);
251
130
    while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
252
  }
253
130
  return true;
254
}
255
256
12165
void MainThreadInterface::DispatchMessages() {
257
12165
  if (dispatching_messages_)
258
12298
    return;
259
12032
  dispatching_messages_ = true;
260
12032
  bool had_messages = false;
261
18283
  do {
262
18283
    if (dispatching_message_queue_.empty()) {
263
18283
      Mutex::ScopedLock scoped_lock(requests_lock_);
264
18283
      requests_.swap(dispatching_message_queue_);
265
    }
266
18283
    had_messages = !dispatching_message_queue_.empty();
267
43073
    while (!dispatching_message_queue_.empty()) {
268
6507
      MessageQueue::value_type task;
269
6507
      std::swap(dispatching_message_queue_.front(), task);
270
6507
      dispatching_message_queue_.pop_front();
271
272
13014
      v8::SealHandleScope seal_handle_scope(isolate_);
273
6507
      task->Call(this);
274
6507
    }
275
  } while (had_messages);
276
12032
  dispatching_messages_ = false;
277
}
278
279
10523
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
280
10523
  if (handle_ == nullptr)
281
5098
    handle_ = std::make_shared<MainThreadHandle>(this);
282
10525
  return handle_;
283
}
284
285
5392
void MainThreadInterface::AddObject(int id,
286
                                    std::unique_ptr<Deletable> object) {
287
5392
  CHECK_NOT_NULL(object);
288
5391
  managed_objects_[id] = std::move(object);
289
5392
}
290
291
264
void MainThreadInterface::RemoveObject(int id) {
292
264
  CHECK_EQ(1, managed_objects_.erase(id));
293
264
}
294
295
440
Deletable* MainThreadInterface::GetObject(int id) {
296
440
  Deletable* pointer = GetObjectIfExists(id);
297
  // This would mean the object is requested after it was disposed, which is
298
  // a coding error.
299
440
  CHECK_NOT_NULL(pointer);
300
440
  return pointer;
301
}
302
303
444
Deletable* MainThreadInterface::GetObjectIfExists(int id) {
304
444
  auto iterator = managed_objects_.find(id);
305
444
  if (iterator == managed_objects_.end()) {
306
    return nullptr;
307
  }
308
444
  return iterator->second.get();
309
}
310
311
72489
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
312
  icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
313
72489
      icu::StringPiece(message.data(), message.length()));
314
72491
  StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
315
144980
                  utf16.length());
316
72490
  return StringBuffer::create(view);
317
}
318
319
31
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
320
    std::unique_ptr<InspectorSessionDelegate> delegate,
321
    bool prevent_shutdown) {
322
  return std::unique_ptr<InspectorSession>(
323
      new CrossThreadInspectorSession(++next_session_id_,
324
                                      shared_from_this(),
325
31
                                      std::move(delegate),
326
62
                                      prevent_shutdown));
327
}
328
329
11195
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
330
11195
  Mutex::ScopedLock scoped_lock(block_lock_);
331
11196
  if (!main_thread_)
332
4689
    return false;
333
6507
  main_thread_->Post(std::move(request));
334
6507
  return true;
335
}
336
337
4662
void MainThreadHandle::Reset() {
338
4662
  Mutex::ScopedLock scoped_lock(block_lock_);
339
4662
  main_thread_ = nullptr;
340
4662
}
341
342
std::unique_ptr<InspectorSessionDelegate>
343
14
MainThreadHandle::MakeDelegateThreadSafe(
344
    std::unique_ptr<InspectorSessionDelegate> delegate) {
345
14
  int id = newObjectId();
346
14
  main_thread_->AddObject(id, WrapInDeletable(std::move(delegate)));
347
  return std::unique_ptr<InspectorSessionDelegate>(
348
14
      new ThreadSafeDelegate(shared_from_this(), id));
349
}
350
351
207
bool MainThreadHandle::Expired() {
352
207
  Mutex::ScopedLock scoped_lock(block_lock_);
353
207
  return main_thread_ == nullptr;
354
}
355
}  // namespace inspector
356
}  // namespace node