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-03-02 22:23:06 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
6
#include <functional>
7
#include <unicode/unistr.h>
8
#include "util-inl.h"
9
10
namespace node {
11
namespace inspector {
12
namespace {
13
14
using v8_inspector::StringView;
15
using v8_inspector::StringBuffer;
16
17
template <typename T>
18
class DeletableWrapper : public Deletable {
19
 public:
20
21
  explicit DeletableWrapper(std::unique_ptr<T> object)
21
21
                        : object_(std::move(object)) {}
22

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

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

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

9428
    if (isolate_ != nullptr && platform_ != nullptr) {
233
      std::shared_ptr<v8::TaskRunner> taskrunner =
234
9428
        platform_->GetForegroundTaskRunner(isolate_);
235
9428
      taskrunner->PostTask(std::make_unique<DispatchMessagesTask>(this));
236
20156
      isolate_->RequestInterrupt([](v8::Isolate* isolate, void* thread) {
237
5364
        static_cast<MainThreadInterface*>(thread)->DispatchMessages();
238
29584
      }, this);
239
    }
240
  }
241
9479
  incoming_message_cond_.Broadcast(scoped_lock);
242
9479
}
243
244
85
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
85
  dispatching_messages_ = false;
249
85
  if (dispatching_message_queue_.empty()) {
250
85
    Mutex::ScopedLock scoped_lock(requests_lock_);
251
85
    while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
252
  }
253
85
  return true;
254
}
255
256
14533
void MainThreadInterface::DispatchMessages() {
257
14533
  if (dispatching_messages_)
258
14655
    return;
259
14412
  dispatching_messages_ = true;
260
14412
  bool had_messages = false;
261
23841
  do {
262
23840
    if (dispatching_message_queue_.empty()) {
263
23841
      Mutex::ScopedLock scoped_lock(requests_lock_);
264
23842
      requests_.swap(dispatching_message_queue_);
265
    }
266
23840
    had_messages = !dispatching_message_queue_.empty();
267
57161
    while (!dispatching_message_queue_.empty()) {
268
9473
      MessageQueue::value_type task;
269
9473
      std::swap(dispatching_message_queue_.front(), task);
270
9456
      dispatching_message_queue_.pop_front();
271
9476
      task->Call(this);
272
9479
    }
273
  } while (had_messages);
274
14413
  dispatching_messages_ = false;
275
}
276
277
9276
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
278
9276
  if (handle_ == nullptr)
279
4414
    handle_ = std::make_shared<MainThreadHandle>(this);
280
9276
  return handle_;
281
}
282
283
4639
void MainThreadInterface::AddObject(int id,
284
                                    std::unique_ptr<Deletable> object) {
285
4639
  CHECK_NOT_NULL(object);
286
4639
  managed_objects_[id] = std::move(object);
287
4639
}
288
289
4263
void MainThreadInterface::RemoveObject(int id) {
290
4263
  CHECK_EQ(1, managed_objects_.erase(id));
291
4263
}
292
293
228
Deletable* MainThreadInterface::GetObject(int id) {
294
228
  Deletable* pointer = GetObjectIfExists(id);
295
  // This would mean the object is requested after it was disposed, which is
296
  // a coding error.
297
228
  CHECK_NOT_NULL(pointer);
298
228
  return pointer;
299
}
300
301
232
Deletable* MainThreadInterface::GetObjectIfExists(int id) {
302
232
  auto iterator = managed_objects_.find(id);
303
232
  if (iterator == managed_objects_.end()) {
304
    return nullptr;
305
  }
306
232
  return iterator->second.get();
307
}
308
309
82938
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
310
  icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
311
82938
      icu::StringPiece(message.data(), message.length()));
312
82939
  StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
313
165878
                  utf16.length());
314
82939
  return StringBuffer::create(view);
315
}
316
317
17
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
318
    std::unique_ptr<InspectorSessionDelegate> delegate,
319
    bool prevent_shutdown) {
320
  return std::unique_ptr<InspectorSession>(
321
      new CrossThreadInspectorSession(++next_session_id_,
322
                                      shared_from_this(),
323
17
                                      std::move(delegate),
324
34
                                      prevent_shutdown));
325
}
326
327
9486
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
328
9486
  Mutex::ScopedLock scoped_lock(block_lock_);
329
9487
  if (!main_thread_)
330
8
    return false;
331
9479
  main_thread_->Post(std::move(request));
332
9479
  return true;
333
}
334
335
4046
void MainThreadHandle::Reset() {
336
4046
  Mutex::ScopedLock scoped_lock(block_lock_);
337
4046
  main_thread_ = nullptr;
338
4046
}
339
340
std::unique_ptr<InspectorSessionDelegate>
341
4
MainThreadHandle::MakeDelegateThreadSafe(
342
    std::unique_ptr<InspectorSessionDelegate> delegate) {
343
4
  int id = newObjectId();
344
4
  main_thread_->AddObject(id, WrapInDeletable(std::move(delegate)));
345
  return std::unique_ptr<InspectorSessionDelegate>(
346
4
      new ThreadSafeDelegate(shared_from_this(), id));
347
}
348
349
172
bool MainThreadHandle::Expired() {
350
172
  Mutex::ScopedLock scoped_lock(block_lock_);
351
172
  return main_thread_ == nullptr;
352
}
353
}  // namespace inspector
354
}  // namespace node