GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/inspector_js_api.cc Lines: 177 180 98.3 %
Date: 2019-01-07 12:15:22 Branches: 54 94 57.4 %

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

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


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


15
  if (args.Length() > 1 && args[1]->IsString()) {
250
    Utf8Value host(env->isolate(), args[1].As<String>());
251
    agent->host_port()->set_host(*host);
252
  }
253
254


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