GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/inspector_js_api.cc Lines: 193 196 98.5 %
Date: 2020-02-27 22:14:15 Branches: 48 82 58.5 %

Line Branch Exec Source
1
#include "base_object-inl.h"
2
#include "inspector_agent.h"
3
#include "inspector_io.h"
4
#include "memory_tracker-inl.h"
5
#include "util-inl.h"
6
#include "v8.h"
7
#include "v8-inspector.h"
8
9
#include <memory>
10
11
namespace node {
12
namespace inspector {
13
namespace {
14
15
using v8::Boolean;
16
using v8::Context;
17
using v8::Function;
18
using v8::FunctionCallbackInfo;
19
using v8::FunctionTemplate;
20
using v8::Global;
21
using v8::HandleScope;
22
using v8::Isolate;
23
using v8::Local;
24
using v8::MaybeLocal;
25
using v8::NewStringType;
26
using v8::Object;
27
using v8::String;
28
using v8::Uint32;
29
using v8::Value;
30
31
using v8_inspector::StringBuffer;
32
using v8_inspector::StringView;
33
34
478
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
35
                                               Local<Value> value) {
36
956
  TwoByteValue buffer(isolate, value);
37
956
  return StringBuffer::create(StringView(*buffer, buffer.length()));
38
}
39
40
struct LocalConnection {
41
267
  static std::unique_ptr<InspectorSession> Connect(
42
      Agent* inspector, std::unique_ptr<InspectorSessionDelegate> delegate) {
43
267
    return inspector->Connect(std::move(delegate), false);
44
  }
45
46
4392
  static Local<String> GetClassName(Environment* env) {
47
4392
    return FIXED_ONE_BYTE_STRING(env->isolate(), "Connection");
48
  }
49
};
50
51
struct MainThreadConnection {
52
2
  static std::unique_ptr<InspectorSession> Connect(
53
      Agent* inspector, std::unique_ptr<InspectorSessionDelegate> delegate) {
54
2
    return inspector->ConnectToMainThread(std::move(delegate), true);
55
  }
56
57
4392
  static Local<String> GetClassName(Environment* env) {
58
4392
    return FIXED_ONE_BYTE_STRING(env->isolate(), "MainThreadConnection");
59
  }
60
};
61
62
template <typename ConnectionType>
63
807
class JSBindingsConnection : public AsyncWrap {
64
 public:
65
538
  class JSBindingsSessionDelegate : public InspectorSessionDelegate {
66
   public:
67
269
    JSBindingsSessionDelegate(Environment* env,
68
                              JSBindingsConnection* connection)
69
                              : env_(env),
70
269
                                connection_(connection) {
71
269
    }
72
73
4617
    void SendMessageToFrontend(const v8_inspector::StringView& message)
74
        override {
75
4617
      Isolate* isolate = env_->isolate();
76
9234
      HandleScope handle_scope(isolate);
77
4617
      Context::Scope context_scope(env_->context());
78
      MaybeLocal<String> v8string =
79
4617
          String::NewFromTwoByte(isolate, message.characters16(),
80
9234
                                 NewStringType::kNormal, message.length());
81
9234
      Local<Value> argument = v8string.ToLocalChecked().As<Value>();
82
4617
      connection_->OnMessage(argument);
83
4617
    }
84
85
   private:
86
    Environment* env_;
87
    JSBindingsConnection* connection_;
88
  };
89
90
269
  JSBindingsConnection(Environment* env,
91
                       Local<Object> wrap,
92
                       Local<Function> callback)
93
                       : AsyncWrap(env, wrap, PROVIDER_INSPECTORJSBINDING),
94
269
                         callback_(env->isolate(), callback) {
95
269
    Agent* inspector = env->inspector_agent();
96
269
    session_ = ConnectionType::Connect(
97
        inspector, std::make_unique<JSBindingsSessionDelegate>(env, this));
98
269
  }
99
100
4617
  void OnMessage(Local<Value> value) {
101
9234
    MakeCallback(callback_.Get(env()->isolate()), 1, &value);
102
4617
  }
103
104
8784
  static void Bind(Environment* env, Local<Object> target) {
105
8784
    Local<String> class_name = ConnectionType::GetClassName(env);
106
    Local<FunctionTemplate> tmpl =
107
8784
        env->NewFunctionTemplate(JSBindingsConnection::New);
108
17568
    tmpl->InstanceTemplate()->SetInternalFieldCount(1);
109
8784
    tmpl->SetClassName(class_name);
110
17568
    tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
111
8784
    env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
112
8784
    env->SetProtoMethod(tmpl, "disconnect", JSBindingsConnection::Disconnect);
113
26352
    target->Set(env->context(),
114
                class_name,
115
26352
                tmpl->GetFunction(env->context()).ToLocalChecked())
116
        .ToChecked();
117
8784
  }
118
119
269
  static void New(const FunctionCallbackInfo<Value>& info) {
120
269
    Environment* env = Environment::GetCurrent(info);
121

538
    CHECK(info[0]->IsFunction());
122
538
    Local<Function> callback = info[0].As<Function>();
123
269
    new JSBindingsConnection(env, info.This(), callback);
124
269
  }
125
126
256
  void Disconnect() {
127
256
    session_.reset();
128

256
    delete this;
129
256
  }
130
131
256
  static void Disconnect(const FunctionCallbackInfo<Value>& info) {
132
    JSBindingsConnection* session;
133

256
    ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
134
256
    session->Disconnect();
135
  }
136
137
478
  static void Dispatch(const FunctionCallbackInfo<Value>& info) {
138
478
    Environment* env = Environment::GetCurrent(info);
139
    JSBindingsConnection* session;
140

478
    ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
141

1434
    CHECK(info[0]->IsString());
142
143

478
    if (session->session_) {
144
956
      session->session_->Dispatch(
145
956
          ToProtocolString(env->isolate(), info[0])->string());
146
    }
147
  }
148
149
2
  void MemoryInfo(MemoryTracker* tracker) const override {
150
2
    tracker->TrackField("callback", callback_);
151
2
    tracker->TrackFieldWithSize(
152
        "session", sizeof(*session_), "InspectorSession");
153
2
  }
154
155
2
  SET_MEMORY_INFO_NAME(JSBindingsConnection)
156
2
  SET_SELF_SIZE(JSBindingsConnection)
157
158
 private:
159
  std::unique_ptr<InspectorSession> session_;
160
  Global<Function> callback_;
161
};
162
163
27160
static bool InspectorEnabled(Environment* env) {
164
27160
  Agent* agent = env->inspector_agent();
165
27160
  return agent->IsActive();
166
}
167
168
4392
void SetConsoleExtensionInstaller(const FunctionCallbackInfo<Value>& info) {
169
4392
  auto env = Environment::GetCurrent(info);
170
171
4392
  CHECK_EQ(info.Length(), 1);
172
8784
  CHECK(info[0]->IsFunction());
173
174
8784
  env->set_inspector_console_extension_installer(info[0].As<Function>());
175
4392
}
176
177
6
void CallAndPauseOnStart(const FunctionCallbackInfo<v8::Value>& args) {
178
6
  Environment* env = Environment::GetCurrent(args);
179
6
  CHECK_GT(args.Length(), 1);
180
12
  CHECK(args[0]->IsFunction());
181
11
  SlicedArguments call_args(args, /* start */ 2);
182
6
  env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
183
  v8::MaybeLocal<v8::Value> retval =
184
17
      args[0].As<v8::Function>()->Call(env->context(), args[1],
185
18
                                       call_args.length(), call_args.out());
186
5
  if (!retval.IsEmpty()) {
187
8
    args.GetReturnValue().Set(retval.ToLocalChecked());
188
  }
189
5
}
190
191
27158
void InspectorConsoleCall(const FunctionCallbackInfo<Value>& info) {
192
27158
  Environment* env = Environment::GetCurrent(info);
193
27158
  Isolate* isolate = env->isolate();
194
27158
  Local<Context> context = isolate->GetCurrentContext();
195
27158
  CHECK_GE(info.Length(), 2);
196
54307
  SlicedArguments call_args(info, /* start */ 2);
197
27158
  if (InspectorEnabled(env)) {
198
27133
    Local<Value> inspector_method = info[0];
199
27133
    CHECK(inspector_method->IsFunction());
200
27133
    if (!env->is_in_inspector_console_call()) {
201
27132
      env->set_is_in_inspector_console_call(true);
202
      MaybeLocal<Value> ret =
203
54264
          inspector_method.As<Function>()->Call(context,
204
                                                info.Holder(),
205
27132
                                                call_args.length(),
206
108528
                                                call_args.out());
207
27132
      env->set_is_in_inspector_console_call(false);
208
27132
      if (ret.IsEmpty())
209
9
        return;
210
    }
211
  }
212
213
27149
  Local<Value> node_method = info[1];
214
27149
  CHECK(node_method->IsFunction());
215
81447
  node_method.As<Function>()->Call(context,
216
                                   info.Holder(),
217
27149
                                   call_args.length(),
218
108596
                                   call_args.out()).FromMaybe(Local<Value>());
219
}
220
221
7
static void* GetAsyncTask(int64_t asyncId) {
222
  // The inspector assumes that when other clients use its asyncTask* API,
223
  // they use real pointers, or at least something aligned like real pointer.
224
  // In general it means that our task_id should always be even.
225
  //
226
  // On 32bit platforms, the 64bit asyncId would get truncated when converted
227
  // to a 32bit pointer. However, the javascript part will never enable
228
  // the async_hook on 32bit platforms, therefore the truncation will never
229
  // happen in practice.
230
7
  return reinterpret_cast<void*>(asyncId << 1);
231
}
232
233
template <void (Agent::*asyncTaskFn)(void*)>
234
6
static void InvokeAsyncTaskFnWithId(const FunctionCallbackInfo<Value>& args) {
235
6
  Environment* env = Environment::GetCurrent(args);
236

12
  CHECK(args[0]->IsNumber());
237
24
  int64_t task_id = args[0]->IntegerValue(env->context()).FromJust();
238
6
  (env->inspector_agent()->*asyncTaskFn)(GetAsyncTask(task_id));
239
6
}
240
241
1
static void AsyncTaskScheduledWrapper(const FunctionCallbackInfo<Value>& args) {
242
1
  Environment* env = Environment::GetCurrent(args);
243
244
3
  CHECK(args[0]->IsString());
245
2
  Local<String> task_name = args[0].As<String>();
246
2
  String::Value task_name_value(args.GetIsolate(), task_name);
247
1
  StringView task_name_view(*task_name_value, task_name_value.length());
248
249
2
  CHECK(args[1]->IsNumber());
250
4
  int64_t task_id = args[1]->IntegerValue(env->context()).FromJust();
251
1
  void* task = GetAsyncTask(task_id);
252
253
2
  CHECK(args[2]->IsBoolean());
254
3
  bool recurring = args[2]->BooleanValue(args.GetIsolate());
255
256
1
  env->inspector_agent()->AsyncTaskScheduled(task_name_view, task, recurring);
257
1
}
258
259
4368
static void RegisterAsyncHookWrapper(const FunctionCallbackInfo<Value>& args) {
260
4368
  Environment* env = Environment::GetCurrent(args);
261
262
8736
  CHECK(args[0]->IsFunction());
263
8736
  Local<Function> enable_function = args[0].As<Function>();
264
8736
  CHECK(args[1]->IsFunction());
265
8736
  Local<Function> disable_function = args[1].As<Function>();
266
4368
  env->inspector_agent()->RegisterAsyncHook(env->isolate(),
267
4368
    enable_function, disable_function);
268
4368
}
269
270
2
void IsEnabled(const FunctionCallbackInfo<Value>& args) {
271
2
  Environment* env = Environment::GetCurrent(args);
272
6
  args.GetReturnValue().Set(InspectorEnabled(env));
273
2
}
274
275
4
void Open(const FunctionCallbackInfo<Value>& args) {
276
4
  Environment* env = Environment::GetCurrent(args);
277
4
  Agent* agent = env->inspector_agent();
278
279

12
  if (args.Length() > 0 && args[0]->IsUint32()) {
280
6
    uint32_t port = args[0].As<Uint32>()->Value();
281
4
    ExclusiveAccess<HostPort>::Scoped host_port(agent->host_port());
282
2
    host_port->set_port(static_cast<int>(port));
283
  }
284
285

16
  if (args.Length() > 1 && args[1]->IsString()) {
286
    Utf8Value host(env->isolate(), args[1].As<String>());
287
    ExclusiveAccess<HostPort>::Scoped host_port(agent->host_port());
288
    host_port->set_host(*host);
289
  }
290
291
4
  agent->StartIoThread();
292
4
}
293
294
2
void WaitForDebugger(const FunctionCallbackInfo<Value>& args) {
295
2
  Environment* env = Environment::GetCurrent(args);
296
2
  Agent* agent = env->inspector_agent();
297
2
  if (agent->IsActive())
298
2
    agent->WaitForConnect();
299
6
  args.GetReturnValue().Set(agent->IsActive());
300
2
}
301
302
9
void Url(const FunctionCallbackInfo<Value>& args) {
303
9
  Environment* env = Environment::GetCurrent(args);
304
16
  std::string url = env->inspector_agent()->GetWsUrl();
305
9
  if (url.length() == 0) {
306
2
    return;
307
  }
308
21
  args.GetReturnValue().Set(OneByteString(env->isolate(), url.c_str()));
309
}
310
311
4392
void Initialize(Local<Object> target, Local<Value> unused,
312
                Local<Context> context, void* priv) {
313
4392
  Environment* env = Environment::GetCurrent(context);
314
315
  v8::Local<v8::Function> consoleCallFunc =
316
8784
      env->NewFunctionTemplate(InspectorConsoleCall, v8::Local<v8::Signature>(),
317
                               v8::ConstructorBehavior::kThrow,
318
4392
                               v8::SideEffectType::kHasSideEffect)
319
8784
          ->GetFunction(context)
320
4392
          .ToLocalChecked();
321
4392
  auto name_string = FIXED_ONE_BYTE_STRING(env->isolate(), "consoleCall");
322
8784
  target->Set(context, name_string, consoleCallFunc).Check();
323
4392
  consoleCallFunc->SetName(name_string);
324
325
  env->SetMethod(
326
4392
      target, "setConsoleExtensionInstaller", SetConsoleExtensionInstaller);
327
4392
  env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
328
4392
  env->SetMethod(target, "open", Open);
329
4392
  env->SetMethodNoSideEffect(target, "url", Url);
330
4392
  env->SetMethod(target, "waitForDebugger", WaitForDebugger);
331
332
4392
  env->SetMethod(target, "asyncTaskScheduled", AsyncTaskScheduledWrapper);
333
  env->SetMethod(target, "asyncTaskCanceled",
334
4392
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskCanceled>);
335
  env->SetMethod(target, "asyncTaskStarted",
336
4392
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskStarted>);
337
  env->SetMethod(target, "asyncTaskFinished",
338
4392
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskFinished>);
339
340
4392
  env->SetMethod(target, "registerAsyncHook", RegisterAsyncHookWrapper);
341
4392
  env->SetMethodNoSideEffect(target, "isEnabled", IsEnabled);
342
343
4392
  JSBindingsConnection<LocalConnection>::Bind(env, target);
344
4392
  JSBindingsConnection<MainThreadConnection>::Bind(env, target);
345
4392
}
346
347
}  // namespace
348
}  // namespace inspector
349
}  // namespace node
350
351
4201
NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector,
352
                                  node::inspector::Initialize)