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: 176 179 98.3 %
Date: 2019-05-05 22:32:45 Branches: 50 88 56.8 %

Line Branch Exec Source
1
#include "base_object-inl.h"
2
#include "inspector_agent.h"
3
#include "inspector_io.h"
4
#include "v8.h"
5
#include "v8-inspector.h"
6
7
#include <memory>
8
9
namespace node {
10
namespace inspector {
11
namespace {
12
13
using v8::Boolean;
14
using v8::Context;
15
using v8::Function;
16
using v8::FunctionCallbackInfo;
17
using v8::FunctionTemplate;
18
using v8::Global;
19
using v8::HandleScope;
20
using v8::Isolate;
21
using v8::Local;
22
using v8::MaybeLocal;
23
using v8::NewStringType;
24
using v8::Object;
25
using v8::String;
26
using v8::Uint32;
27
using v8::Value;
28
29
using v8_inspector::StringBuffer;
30
using v8_inspector::StringView;
31
32
394
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
33
                                               Local<Value> value) {
34
394
  TwoByteValue buffer(isolate, value);
35
394
  return StringBuffer::create(StringView(*buffer, buffer.length()));
36
}
37
38
582
class JSBindingsConnection : public AsyncWrap {
39
 public:
40
388
  class JSBindingsSessionDelegate : public InspectorSessionDelegate {
41
   public:
42
194
    JSBindingsSessionDelegate(Environment* env,
43
                              JSBindingsConnection* connection)
44
                              : env_(env),
45
194
                                connection_(connection) {
46
194
    }
47
48
3698
    void SendMessageToFrontend(const v8_inspector::StringView& message)
49
        override {
50
3698
      Isolate* isolate = env_->isolate();
51
3698
      HandleScope handle_scope(isolate);
52
3698
      Context::Scope context_scope(env_->context());
53
      MaybeLocal<String> v8string =
54
          String::NewFromTwoByte(isolate, message.characters16(),
55
3698
                                 NewStringType::kNormal, message.length());
56
7396
      Local<Value> argument = v8string.ToLocalChecked().As<Value>();
57
7396
      connection_->OnMessage(argument);
58
3698
    }
59
60
   private:
61
    Environment* env_;
62
    JSBindingsConnection* connection_;
63
  };
64
65
194
  JSBindingsConnection(Environment* env,
66
                       Local<Object> wrap,
67
                       Local<Function> callback)
68
                       : AsyncWrap(env, wrap, PROVIDER_INSPECTORJSBINDING),
69
194
                         callback_(env->isolate(), callback) {
70
194
    Agent* inspector = env->inspector_agent();
71
388
    session_ = inspector->Connect(std::make_unique<JSBindingsSessionDelegate>(
72
194
        env, this), false);
73
194
  }
74
75
3698
  void OnMessage(Local<Value> value) {
76
7396
    MakeCallback(callback_.Get(env()->isolate()), 1, &value);
77
3698
  }
78
79
194
  static void New(const FunctionCallbackInfo<Value>& info) {
80
194
    Environment* env = Environment::GetCurrent(info);
81
388
    CHECK(info[0]->IsFunction());
82
388
    Local<Function> callback = info[0].As<Function>();
83
194
    new JSBindingsConnection(env, info.This(), callback);
84
194
  }
85
86
189
  void Disconnect() {
87
189
    session_.reset();
88
189
    delete this;
89
189
  }
90
91
189
  static void Disconnect(const FunctionCallbackInfo<Value>& info) {
92
    JSBindingsConnection* session;
93
378
    ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
94
189
    session->Disconnect();
95
  }
96
97
394
  static void Dispatch(const FunctionCallbackInfo<Value>& info) {
98
394
    Environment* env = Environment::GetCurrent(info);
99
    JSBindingsConnection* session;
100
788
    ASSIGN_OR_RETURN_UNWRAP(&session, info.Holder());
101
1182
    CHECK(info[0]->IsString());
102
103
394
    if (session->session_) {
104
394
      session->session_->Dispatch(
105
788
          ToProtocolString(env->isolate(), info[0])->string());
106
    }
107
  }
108
109
2
  void MemoryInfo(MemoryTracker* tracker) const override {
110
2
    tracker->TrackField("callback", callback_);
111
    tracker->TrackFieldWithSize(
112
2
        "session", sizeof(*session_), "InspectorSession");
113
2
  }
114
115
2
  SET_MEMORY_INFO_NAME(JSBindingsConnection)
116
2
  SET_SELF_SIZE(JSBindingsConnection)
117
118
 private:
119
  std::unique_ptr<InspectorSession> session_;
120
  Global<Function> callback_;
121
};
122
123
146568
static bool InspectorEnabled(Environment* env) {
124
146568
  Agent* agent = env->inspector_agent();
125
146568
  return agent->IsActive();
126
}
127
128
4645
void SetConsoleExtensionInstaller(const FunctionCallbackInfo<Value>& info) {
129
4645
  auto env = Environment::GetCurrent(info);
130
131
4645
  CHECK_EQ(info.Length(), 1);
132
9290
  CHECK(info[0]->IsFunction());
133
134
9290
  env->set_inspector_console_extension_installer(info[0].As<Function>());
135
4645
}
136
137
5
void CallAndPauseOnStart(const FunctionCallbackInfo<v8::Value>& args) {
138
5
  Environment* env = Environment::GetCurrent(args);
139
5
  CHECK_GT(args.Length(), 1);
140
10
  CHECK(args[0]->IsFunction());
141
5
  SlicedArguments call_args(args, /* start */ 2);
142
5
  env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
143
  v8::MaybeLocal<v8::Value> retval =
144
9
      args[0].As<v8::Function>()->Call(env->context(), args[1],
145
20
                                       call_args.length(), call_args.out());
146
4
  if (!retval.IsEmpty()) {
147
6
    args.GetReturnValue().Set(retval.ToLocalChecked());
148
4
  }
149
4
}
150
151
146566
void InspectorConsoleCall(const FunctionCallbackInfo<Value>& info) {
152
146566
  Environment* env = Environment::GetCurrent(info);
153
146566
  Isolate* isolate = env->isolate();
154
146566
  Local<Context> context = isolate->GetCurrentContext();
155
146566
  CHECK_GE(info.Length(), 2);
156
146566
  SlicedArguments call_args(info, /* start */ 2);
157
146566
  if (InspectorEnabled(env)) {
158
146501
    Local<Value> inspector_method = info[0];
159
146501
    CHECK(inspector_method->IsFunction());
160
146501
    if (!env->is_in_inspector_console_call()) {
161
146500
      env->set_is_in_inspector_console_call(true);
162
      MaybeLocal<Value> ret =
163
          inspector_method.As<Function>()->Call(context,
164
                                                info.Holder(),
165
146500
                                                call_args.length(),
166
586000
                                                call_args.out());
167
146500
      env->set_is_in_inspector_console_call(false);
168
146500
      if (ret.IsEmpty())
169
146566
        return;
170
    }
171
  }
172
173
146566
  Local<Value> node_method = info[1];
174
146566
  CHECK(node_method->IsFunction());
175
  node_method.As<Function>()->Call(context,
176
                                   info.Holder(),
177
146566
                                   call_args.length(),
178
732830
                                   call_args.out()).FromMaybe(Local<Value>());
179
}
180
181
7
static void* GetAsyncTask(int64_t asyncId) {
182
  // The inspector assumes that when other clients use its asyncTask* API,
183
  // they use real pointers, or at least something aligned like real pointer.
184
  // In general it means that our task_id should always be even.
185
  //
186
  // On 32bit platforms, the 64bit asyncId would get truncated when converted
187
  // to a 32bit pointer. However, the javascript part will never enable
188
  // the async_hook on 32bit platforms, therefore the truncation will never
189
  // happen in practice.
190
7
  return reinterpret_cast<void*>(asyncId << 1);
191
}
192
193
template <void (Agent::*asyncTaskFn)(void*)>
194
6
static void InvokeAsyncTaskFnWithId(const FunctionCallbackInfo<Value>& args) {
195
6
  Environment* env = Environment::GetCurrent(args);
196

12
  CHECK(args[0]->IsNumber());
197
24
  int64_t task_id = args[0]->IntegerValue(env->context()).FromJust();
198
6
  (env->inspector_agent()->*asyncTaskFn)(GetAsyncTask(task_id));
199
6
}
200
201
1
static void AsyncTaskScheduledWrapper(const FunctionCallbackInfo<Value>& args) {
202
1
  Environment* env = Environment::GetCurrent(args);
203
204
3
  CHECK(args[0]->IsString());
205
2
  Local<String> task_name = args[0].As<String>();
206
1
  String::Value task_name_value(args.GetIsolate(), task_name);
207
1
  StringView task_name_view(*task_name_value, task_name_value.length());
208
209
2
  CHECK(args[1]->IsNumber());
210
4
  int64_t task_id = args[1]->IntegerValue(env->context()).FromJust();
211
1
  void* task = GetAsyncTask(task_id);
212
213
2
  CHECK(args[2]->IsBoolean());
214
3
  bool recurring = args[2]->BooleanValue(args.GetIsolate());
215
216
1
  env->inspector_agent()->AsyncTaskScheduled(task_name_view, task, recurring);
217
1
}
218
219
4644
static void RegisterAsyncHookWrapper(const FunctionCallbackInfo<Value>& args) {
220
4644
  Environment* env = Environment::GetCurrent(args);
221
222
9288
  CHECK(args[0]->IsFunction());
223
9288
  Local<Function> enable_function = args[0].As<Function>();
224
9288
  CHECK(args[1]->IsFunction());
225
9288
  Local<Function> disable_function = args[1].As<Function>();
226
  env->inspector_agent()->RegisterAsyncHook(env->isolate(),
227
4644
    enable_function, disable_function);
228
4644
}
229
230
2
void IsEnabled(const FunctionCallbackInfo<Value>& args) {
231
2
  Environment* env = Environment::GetCurrent(args);
232
6
  args.GetReturnValue().Set(InspectorEnabled(env));
233
2
}
234
235
3
void Open(const FunctionCallbackInfo<Value>& args) {
236
3
  Environment* env = Environment::GetCurrent(args);
237
3
  Agent* agent = env->inspector_agent();
238
3
  bool wait_for_connect = false;
239
240


12
  if (args.Length() > 0 && args[0]->IsUint32()) {
241
3
    uint32_t port = args[0].As<Uint32>()->Value();
242
1
    agent->host_port()->set_port(static_cast<int>(port));
243
  }
244
245


15
  if (args.Length() > 1 && args[1]->IsString()) {
246
    Utf8Value host(env->isolate(), args[1].As<String>());
247
    agent->host_port()->set_host(*host);
248
  }
249
250


12
  if (args.Length() > 2 && args[2]->IsBoolean()) {
251
9
    wait_for_connect = args[2]->BooleanValue(args.GetIsolate());
252
  }
253
3
  agent->StartIoThread();
254
3
  if (wait_for_connect)
255
    agent->WaitForConnect();
256
3
}
257
258
5
void Url(const FunctionCallbackInfo<Value>& args) {
259
5
  Environment* env = Environment::GetCurrent(args);
260
5
  Agent* agent = env->inspector_agent();
261
5
  InspectorIo* io = agent->io();
262
263
7
  if (!io) return;
264
265
3
  std::vector<std::string> ids = io->GetTargetIds();
266
267
3
  if (ids.empty()) return;
268
269
6
  std::string url = FormatWsAddress(io->host(), io->port(), ids[0], true);
270
12
  args.GetReturnValue().Set(OneByteString(env->isolate(), url.c_str()));
271
}
272
273
4645
void Initialize(Local<Object> target, Local<Value> unused,
274
                Local<Context> context, void* priv) {
275
4645
  Environment* env = Environment::GetCurrent(context);
276
277
  v8::Local<v8::Function> consoleCallFunc =
278
      env->NewFunctionTemplate(InspectorConsoleCall, v8::Local<v8::Signature>(),
279
                               v8::ConstructorBehavior::kThrow,
280
4645
                               v8::SideEffectType::kHasSideEffect)
281
13935
          ->GetFunction(context)
282
9290
          .ToLocalChecked();
283
4645
  auto name_string = FIXED_ONE_BYTE_STRING(env->isolate(), "consoleCall");
284
9290
  target->Set(context, name_string, consoleCallFunc).Check();
285
4645
  consoleCallFunc->SetName(name_string);
286
287
  env->SetMethod(
288
4645
      target, "setConsoleExtensionInstaller", SetConsoleExtensionInstaller);
289
4645
  env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
290
4645
  env->SetMethod(target, "open", Open);
291
4645
  env->SetMethodNoSideEffect(target, "url", Url);
292
293
4645
  env->SetMethod(target, "asyncTaskScheduled", AsyncTaskScheduledWrapper);
294
  env->SetMethod(target, "asyncTaskCanceled",
295
4645
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskCanceled>);
296
  env->SetMethod(target, "asyncTaskStarted",
297
4645
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskStarted>);
298
  env->SetMethod(target, "asyncTaskFinished",
299
4645
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskFinished>);
300
301
4645
  env->SetMethod(target, "registerAsyncHook", RegisterAsyncHookWrapper);
302
4645
  env->SetMethodNoSideEffect(target, "isEnabled", IsEnabled);
303
304
4645
  auto conn_str = FIXED_ONE_BYTE_STRING(env->isolate(), "Connection");
305
  Local<FunctionTemplate> tmpl =
306
4645
      env->NewFunctionTemplate(JSBindingsConnection::New);
307
9290
  tmpl->InstanceTemplate()->SetInternalFieldCount(1);
308
4645
  tmpl->SetClassName(conn_str);
309
9290
  tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
310
4645
  env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
311
4645
  env->SetProtoMethod(tmpl, "disconnect", JSBindingsConnection::Disconnect);
312
  target
313
      ->Set(env->context(), conn_str,
314
23225
            tmpl->GetFunction(env->context()).ToLocalChecked())
315
9290
      .ToChecked();
316
4645
}
317
318
}  // namespace
319
}  // namespace inspector
320
}  // namespace node
321
322
4524
NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector,
323
                                  node::inspector::Initialize)