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: 177 179 98.9 %
Date: 2019-07-27 22:37:30 Branches: 46 78 59.0 %

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

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


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


20
  if (args.Length() > 1 && args[1]->IsString()) {
247
    Utf8Value host(env->isolate(), args[1].As<String>());
248
    agent->host_port()->set_host(*host);
249
  }
250
251
4
  agent->StartIoThread();
252
4
}
253
254
2
void WaitForDebugger(const FunctionCallbackInfo<Value>& args) {
255
2
  Environment* env = Environment::GetCurrent(args);
256
2
  Agent* agent = env->inspector_agent();
257
2
  if (agent->IsActive())
258
2
    agent->WaitForConnect();
259
6
  args.GetReturnValue().Set(agent->IsActive());
260
2
}
261
262
9
void Url(const FunctionCallbackInfo<Value>& args) {
263
9
  Environment* env = Environment::GetCurrent(args);
264
9
  std::string url = env->inspector_agent()->GetWsUrl();
265
9
  if (url.length() == 0) {
266
11
    return;
267
  }
268
21
  args.GetReturnValue().Set(OneByteString(env->isolate(), url.c_str()));
269
}
270
271
4965
void Initialize(Local<Object> target, Local<Value> unused,
272
                Local<Context> context, void* priv) {
273
4965
  Environment* env = Environment::GetCurrent(context);
274
275
  v8::Local<v8::Function> consoleCallFunc =
276
      env->NewFunctionTemplate(InspectorConsoleCall, v8::Local<v8::Signature>(),
277
                               v8::ConstructorBehavior::kThrow,
278
4965
                               v8::SideEffectType::kHasSideEffect)
279
14895
          ->GetFunction(context)
280
9930
          .ToLocalChecked();
281
4965
  auto name_string = FIXED_ONE_BYTE_STRING(env->isolate(), "consoleCall");
282
9930
  target->Set(context, name_string, consoleCallFunc).Check();
283
4965
  consoleCallFunc->SetName(name_string);
284
285
  env->SetMethod(
286
4965
      target, "setConsoleExtensionInstaller", SetConsoleExtensionInstaller);
287
4965
  env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
288
4965
  env->SetMethod(target, "open", Open);
289
4965
  env->SetMethodNoSideEffect(target, "url", Url);
290
4965
  env->SetMethod(target, "waitForDebugger", WaitForDebugger);
291
292
4965
  env->SetMethod(target, "asyncTaskScheduled", AsyncTaskScheduledWrapper);
293
  env->SetMethod(target, "asyncTaskCanceled",
294
4965
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskCanceled>);
295
  env->SetMethod(target, "asyncTaskStarted",
296
4965
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskStarted>);
297
  env->SetMethod(target, "asyncTaskFinished",
298
4965
      InvokeAsyncTaskFnWithId<&Agent::AsyncTaskFinished>);
299
300
4965
  env->SetMethod(target, "registerAsyncHook", RegisterAsyncHookWrapper);
301
4965
  env->SetMethodNoSideEffect(target, "isEnabled", IsEnabled);
302
303
4965
  auto conn_str = FIXED_ONE_BYTE_STRING(env->isolate(), "Connection");
304
  Local<FunctionTemplate> tmpl =
305
4965
      env->NewFunctionTemplate(JSBindingsConnection::New);
306
9930
  tmpl->InstanceTemplate()->SetInternalFieldCount(1);
307
4965
  tmpl->SetClassName(conn_str);
308
9930
  tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
309
4965
  env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
310
4965
  env->SetProtoMethod(tmpl, "disconnect", JSBindingsConnection::Disconnect);
311
  target
312
      ->Set(env->context(), conn_str,
313
24825
            tmpl->GetFunction(env->context()).ToLocalChecked())
314
9930
      .ToChecked();
315
4965
}
316
317
}  // namespace
318
}  // namespace inspector
319
}  // namespace node
320
321
4831
NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector,
322
                                  node::inspector::Initialize)