Coverage Report

Created: 2025-07-04 09:33

/src/node/src/inspector/main_thread_interface.cc
Line
Count
Source (jump to first uncovered line)
1
#include "main_thread_interface.h"
2
3
#include "env-inl.h"
4
#include "simdutf.h"
5
#include "v8-inspector.h"
6
7
#include <functional>
8
#include <memory>
9
10
namespace node {
11
namespace inspector {
12
namespace {
13
14
using v8_inspector::StringBuffer;
15
using v8_inspector::StringView;
16
17
template <typename T>
18
class DeletableWrapper : public Deletable {
19
 public:
20
  explicit DeletableWrapper(std::unique_ptr<T> object)
21
0
                        : object_(std::move(object)) {}
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::(anonymous namespace)::MainThreadSessionState>::DeletableWrapper(std::__1::unique_ptr<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::default_delete<node::inspector::(anonymous namespace)::MainThreadSessionState> >)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::InspectorSessionDelegate>::DeletableWrapper(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >)
22
0
  ~DeletableWrapper() override = default;
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::(anonymous namespace)::MainThreadSessionState>::~DeletableWrapper()
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::InspectorSessionDelegate>::~DeletableWrapper()
23
24
0
  static T* get(MainThreadInterface* thread, int id) {
25
0
    return
26
0
        static_cast<DeletableWrapper<T>*>(thread->GetObject(id))->object_.get();
27
0
  }
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::(anonymous namespace)::MainThreadSessionState>::get(node::inspector::MainThreadInterface*, int)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::DeletableWrapper<node::inspector::InspectorSessionDelegate>::get(node::inspector::MainThreadInterface*, int)
28
29
 private:
30
  std::unique_ptr<T> object_;
31
};
32
33
template <typename T>
34
0
std::unique_ptr<Deletable> WrapInDeletable(std::unique_ptr<T> object) {
35
0
  return std::unique_ptr<DeletableWrapper<T>>(
36
0
      new DeletableWrapper<T>(std::move(object)));
37
0
}
Unexecuted instantiation: main_thread_interface.cc:std::__1::unique_ptr<node::inspector::Deletable, std::__1::default_delete<node::inspector::Deletable> > node::inspector::(anonymous namespace)::WrapInDeletable<node::inspector::(anonymous namespace)::MainThreadSessionState>(std::__1::unique_ptr<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::default_delete<node::inspector::(anonymous namespace)::MainThreadSessionState> >)
Unexecuted instantiation: main_thread_interface.cc:std::__1::unique_ptr<node::inspector::Deletable, std::__1::default_delete<node::inspector::Deletable> > node::inspector::(anonymous namespace)::WrapInDeletable<node::inspector::InspectorSessionDelegate>(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >)
38
39
template <typename Factory>
40
class CreateObjectRequest : public Request {
41
 public:
42
  CreateObjectRequest(int object_id, Factory factory)
43
0
                      : object_id_(object_id), factory_(std::move(factory)) {}
44
45
0
  void Call(MainThreadInterface* thread) override {
46
0
    thread->AddObject(object_id_, WrapInDeletable(factory_(thread)));
47
0
  }
48
49
 private:
50
  int object_id_;
51
  Factory factory_;
52
};
53
54
template <typename Factory>
55
0
std::unique_ptr<Request> NewCreateRequest(int object_id, Factory factory) {
56
0
  return std::unique_ptr<Request>(
57
0
      new CreateObjectRequest<Factory>(object_id, std::move(factory)));
58
0
}
59
60
class DeleteRequest : public Request {
61
 public:
62
0
  explicit DeleteRequest(int object_id) : object_id_(object_id) {}
63
64
0
  void Call(MainThreadInterface* thread) override {
65
0
    thread->RemoveObject(object_id_);
66
0
  }
67
68
 private:
69
  int object_id_;
70
};
71
72
template <typename Target, typename Fn>
73
class CallRequest : public Request {
74
 public:
75
0
  CallRequest(int id, Fn fn) : id_(id), fn_(std::move(fn)) {}
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > > >::CallRequest(int, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > >)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > > >::CallRequest(int, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > >)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::InspectorSessionDelegate, node::inspector::(anonymous namespace)::ThreadSafeDelegate::SendMessageToFrontend(v8_inspector::StringView const&)::{lambda(node::inspector::InspectorSessionDelegate*)#1}>::CallRequest(int, {lambda(node::inspector::InspectorSessionDelegate*)#1})
76
77
0
  void Call(MainThreadInterface* thread) override {
78
0
    fn_(DeletableWrapper<Target>::get(thread, id_));
79
0
  }
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > > >::Call(node::inspector::MainThreadInterface*)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::(anonymous namespace)::MainThreadSessionState, std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > > >::Call(node::inspector::MainThreadInterface*)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::CallRequest<node::inspector::InspectorSessionDelegate, node::inspector::(anonymous namespace)::ThreadSafeDelegate::SendMessageToFrontend(v8_inspector::StringView const&)::{lambda(node::inspector::InspectorSessionDelegate*)#1}>::Call(node::inspector::MainThreadInterface*)
80
81
 private:
82
  int id_;
83
  Fn fn_;
84
};
85
86
template <typename T>
87
class AnotherThreadObjectReference {
88
 public:
89
  AnotherThreadObjectReference(
90
      std::shared_ptr<MainThreadHandle> thread, int object_id)
91
0
      : thread_(thread), object_id_(object_id) {}
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::AnotherThreadObjectReference(std::__1::shared_ptr<node::inspector::MainThreadHandle>, int)
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::InspectorSessionDelegate>::AnotherThreadObjectReference(std::__1::shared_ptr<node::inspector::MainThreadHandle>, int)
92
93
  template <typename Factory>
94
  AnotherThreadObjectReference(
95
      std::shared_ptr<MainThreadHandle> thread, Factory factory)
96
0
      : AnotherThreadObjectReference(thread, thread->newObjectId()) {
97
0
    thread_->Post(NewCreateRequest(object_id_, std::move(factory)));
98
0
  }
99
  AnotherThreadObjectReference(AnotherThreadObjectReference&) = delete;
100
101
0
  ~AnotherThreadObjectReference() {
102
    // Disappearing thread may cause a memory leak
103
0
    thread_->Post(std::make_unique<DeleteRequest>(object_id_));
104
0
  }
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::~AnotherThreadObjectReference()
Unexecuted instantiation: main_thread_interface.cc:node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::InspectorSessionDelegate>::~AnotherThreadObjectReference()
105
106
  template <typename Fn>
107
0
  void Call(Fn fn) const {
108
0
    using Request = CallRequest<T, Fn>;
109
0
    thread_->Post(std::unique_ptr<Request>(
110
0
        new Request(object_id_, std::move(fn))));
111
0
  }
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Call<std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > > >(std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > >) const
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Call<std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > > >(std::__1::__bind<void (&)(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&), std::__1::placeholders::__ph<1> const&, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*&)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > >) const
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::InspectorSessionDelegate>::Call<node::inspector::(anonymous namespace)::ThreadSafeDelegate::SendMessageToFrontend(v8_inspector::StringView const&)::{lambda(node::inspector::InspectorSessionDelegate*)#1}>(node::inspector::(anonymous namespace)::ThreadSafeDelegate::SendMessageToFrontend(v8_inspector::StringView const&)::{lambda(node::inspector::InspectorSessionDelegate*)#1}) const
112
113
  template <typename Arg>
114
0
  void Call(void (T::*fn)(Arg), Arg argument) const {
115
0
    Call(std::bind(Apply<Arg>, std::placeholders::_1, fn, std::move(argument)));
116
0
  }
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Call<std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > >(void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >) const
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Call<std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > >(void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >) const
117
118
 private:
119
  // This has to use non-const reference to support std::bind with non-copyable
120
  // types
121
  template <typename Argument>
122
  static void Apply(T* target, void (T::*fn)(Argument),
123
0
    /* NOLINT (runtime/references) */ Argument& argument) {
124
0
    (target->*fn)(std::move(argument));
125
0
  }
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Apply<std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> > >(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >), std::__1::unique_ptr<node::inspector::InspectorSessionDelegate, std::__1::default_delete<node::inspector::InspectorSessionDelegate> >&)
Unexecuted instantiation: main_thread_interface.cc:void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Apply<std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > >(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&)
126
127
  std::shared_ptr<MainThreadHandle> thread_;
128
  const int object_id_;
129
};
130
131
class MainThreadSessionState {
132
 public:
133
  MainThreadSessionState(MainThreadInterface* thread, bool prevent_shutdown)
134
0
                         : thread_(thread),
135
0
                           prevent_shutdown_(prevent_shutdown) {}
136
137
  static std::unique_ptr<MainThreadSessionState> Create(
138
0
      MainThreadInterface* thread, bool prevent_shutdown) {
139
0
    return std::make_unique<MainThreadSessionState>(thread, prevent_shutdown);
140
0
  }
141
142
0
  void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) {
143
0
    Agent* agent = thread_->inspector_agent();
144
0
    if (agent != nullptr)
145
0
      session_ = agent->Connect(std::move(delegate), prevent_shutdown_);
146
0
  }
147
148
0
  void Dispatch(std::unique_ptr<StringBuffer> message) {
149
0
    session_->Dispatch(message->string());
150
0
  }
151
152
 private:
153
  MainThreadInterface* thread_;
154
  bool prevent_shutdown_;
155
  std::unique_ptr<InspectorSession> session_;
156
};
157
158
class CrossThreadInspectorSession : public InspectorSession {
159
 public:
160
  CrossThreadInspectorSession(
161
      int id,
162
      std::shared_ptr<MainThreadHandle> thread,
163
      std::unique_ptr<InspectorSessionDelegate> delegate,
164
      bool prevent_shutdown)
165
0
      : state_(thread, std::bind(MainThreadSessionState::Create,
166
0
                                 std::placeholders::_1,
167
0
                                 prevent_shutdown)) {
168
0
    state_.Call(&MainThreadSessionState::Connect, std::move(delegate));
169
0
  }
170
171
0
  void Dispatch(const StringView& message) override {
172
0
    state_.Call(&MainThreadSessionState::Dispatch,
173
0
                StringBuffer::create(message));
174
0
  }
175
176
 private:
177
  AnotherThreadObjectReference<MainThreadSessionState> state_;
178
};
179
180
class ThreadSafeDelegate : public InspectorSessionDelegate {
181
 public:
182
  ThreadSafeDelegate(std::shared_ptr<MainThreadHandle> thread, int object_id)
183
0
                     : thread_(thread), delegate_(thread, object_id) {}
184
185
0
  void SendMessageToFrontend(const v8_inspector::StringView& message) override {
186
0
    delegate_.Call(
187
0
        [m = StringBuffer::create(message)]
188
0
        (InspectorSessionDelegate* delegate) {
189
0
      delegate->SendMessageToFrontend(m->string());
190
0
    });
191
0
  }
192
193
 private:
194
  std::shared_ptr<MainThreadHandle> thread_;
195
  AnotherThreadObjectReference<InspectorSessionDelegate> delegate_;
196
};
197
}  // namespace
198
199
200
0
MainThreadInterface::MainThreadInterface(Agent* agent) : agent_(agent) {}
201
202
0
MainThreadInterface::~MainThreadInterface() {
203
0
  if (handle_)
204
0
    handle_->Reset();
205
0
}
206
207
0
void MainThreadInterface::Post(std::unique_ptr<Request> request) {
208
0
  CHECK_NOT_NULL(agent_);
209
0
  Mutex::ScopedLock scoped_lock(requests_lock_);
210
0
  bool needs_notify = requests_.empty();
211
0
  requests_.push_back(std::move(request));
212
0
  if (needs_notify) {
213
0
    std::weak_ptr<MainThreadInterface> weak_self {shared_from_this()};
214
0
    agent_->env()->RequestInterrupt([weak_self](Environment*) {
215
0
      if (auto iface = weak_self.lock()) iface->DispatchMessages();
216
0
    });
217
0
  }
218
0
  incoming_message_cond_.Broadcast(scoped_lock);
219
0
}
220
221
0
bool MainThreadInterface::WaitForFrontendEvent() {
222
  // We allow DispatchMessages reentry as we enter the pause. This is important
223
  // to support debugging the code invoked by an inspector call, such
224
  // as Runtime.evaluate
225
0
  dispatching_messages_ = false;
226
0
  if (dispatching_message_queue_.empty()) {
227
0
    Mutex::ScopedLock scoped_lock(requests_lock_);
228
0
    while (requests_.empty()) incoming_message_cond_.Wait(scoped_lock);
229
0
  }
230
0
  return true;
231
0
}
232
233
0
void MainThreadInterface::DispatchMessages() {
234
0
  if (dispatching_messages_)
235
0
    return;
236
0
  dispatching_messages_ = true;
237
0
  bool had_messages = false;
238
0
  do {
239
0
    if (dispatching_message_queue_.empty()) {
240
0
      Mutex::ScopedLock scoped_lock(requests_lock_);
241
0
      requests_.swap(dispatching_message_queue_);
242
0
    }
243
0
    had_messages = !dispatching_message_queue_.empty();
244
0
    while (!dispatching_message_queue_.empty()) {
245
0
      MessageQueue::value_type task;
246
0
      std::swap(dispatching_message_queue_.front(), task);
247
0
      dispatching_message_queue_.pop_front();
248
249
0
      v8::SealHandleScope seal_handle_scope(agent_->env()->isolate());
250
0
      task->Call(this);
251
0
    }
252
0
  } while (had_messages);
253
0
  dispatching_messages_ = false;
254
0
}
255
256
0
std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() {
257
0
  if (handle_ == nullptr)
258
0
    handle_ = std::make_shared<MainThreadHandle>(this);
259
0
  return handle_;
260
0
}
261
262
void MainThreadInterface::AddObject(int id,
263
0
                                    std::unique_ptr<Deletable> object) {
264
0
  CHECK_NOT_NULL(object);
265
0
  managed_objects_[id] = std::move(object);
266
0
}
267
268
0
void MainThreadInterface::RemoveObject(int id) {
269
0
  CHECK_EQ(1, managed_objects_.erase(id));
270
0
}
271
272
0
Deletable* MainThreadInterface::GetObject(int id) {
273
0
  Deletable* pointer = GetObjectIfExists(id);
274
  // This would mean the object is requested after it was disposed, which is
275
  // a coding error.
276
0
  CHECK_NOT_NULL(pointer);
277
0
  return pointer;
278
0
}
279
280
0
Deletable* MainThreadInterface::GetObjectIfExists(int id) {
281
0
  auto iterator = managed_objects_.find(id);
282
0
  if (iterator == managed_objects_.end()) {
283
0
    return nullptr;
284
0
  }
285
0
  return iterator->second.get();
286
0
}
287
288
407k
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string_view message) {
289
407k
  size_t expected_u16_length =
290
407k
      simdutf::utf16_length_from_utf8(message.data(), message.length());
291
407k
  MaybeStackBuffer<char16_t> buffer(expected_u16_length);
292
407k
  size_t utf16_length = simdutf::convert_utf8_to_utf16(
293
407k
      message.data(), message.length(), buffer.out());
294
407k
  StringView view(reinterpret_cast<uint16_t*>(buffer.out()), utf16_length);
295
407k
  return StringBuffer::create(view);
296
407k
}
297
298
std::unique_ptr<InspectorSession> MainThreadHandle::Connect(
299
    std::unique_ptr<InspectorSessionDelegate> delegate,
300
0
    bool prevent_shutdown) {
301
0
  return std::unique_ptr<InspectorSession>(
302
0
      new CrossThreadInspectorSession(++next_session_id_,
303
0
                                      shared_from_this(),
304
0
                                      std::move(delegate),
305
0
                                      prevent_shutdown));
306
0
}
307
308
0
bool MainThreadHandle::Post(std::unique_ptr<Request> request) {
309
0
  Mutex::ScopedLock scoped_lock(block_lock_);
310
0
  if (!main_thread_)
311
0
    return false;
312
0
  main_thread_->Post(std::move(request));
313
0
  return true;
314
0
}
315
316
0
void MainThreadHandle::Reset() {
317
0
  Mutex::ScopedLock scoped_lock(block_lock_);
318
0
  main_thread_ = nullptr;
319
0
}
320
321
std::unique_ptr<InspectorSessionDelegate>
322
MainThreadHandle::MakeDelegateThreadSafe(
323
0
    std::unique_ptr<InspectorSessionDelegate> delegate) {
324
0
  int id = newObjectId();
325
0
  main_thread_->AddObject(id, WrapInDeletable(std::move(delegate)));
326
0
  return std::unique_ptr<InspectorSessionDelegate>(
327
0
      new ThreadSafeDelegate(shared_from_this(), id));
328
0
}
329
330
0
bool MainThreadHandle::Expired() {
331
0
  Mutex::ScopedLock scoped_lock(block_lock_);
332
0
  return main_thread_ == nullptr;
333
0
}
334
}  // namespace inspector
335
}  // namespace node