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

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


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


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


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