GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/heap_utils.cc Lines: 205 229 89.5 %
Date: 2019-07-28 22:34:34 Branches: 91 156 58.3 %

Line Branch Exec Source
1
#include "diagnosticfilename-inl.h"
2
#include "env-inl.h"
3
#include "memory_tracker-inl.h"
4
#include "stream_base-inl.h"
5
#include "util-inl.h"
6
7
using v8::Array;
8
using v8::Boolean;
9
using v8::Context;
10
using v8::EmbedderGraph;
11
using v8::EscapableHandleScope;
12
using v8::FunctionCallbackInfo;
13
using v8::FunctionTemplate;
14
using v8::Global;
15
using v8::HandleScope;
16
using v8::HeapSnapshot;
17
using v8::Isolate;
18
using v8::JSON;
19
using v8::Local;
20
using v8::MaybeLocal;
21
using v8::Number;
22
using v8::Object;
23
using v8::ObjectTemplate;
24
using v8::String;
25
using v8::Value;
26
27
namespace node {
28
namespace heap {
29
30
14244
class JSGraphJSNode : public EmbedderGraph::Node {
31
 public:
32
4748
  const char* Name() override { return "<JS Node>"; }
33
4748
  size_t SizeInBytes() override { return 0; }
34
4748
  bool IsEmbedderNode() override { return false; }
35
14244
  Local<Value> JSValue() { return PersistentToLocal::Strong(persistent_); }
36
37
9496
  int IdentityHash() {
38
9496
    Local<Value> v = JSValue();
39
12232
    if (v->IsObject()) return v.As<Object>()->GetIdentityHash();
40
24384
    if (v->IsName()) return v.As<v8::Name>()->GetIdentityHash();
41
    if (v->IsInt32()) return v.As<v8::Int32>()->Value();
42
    return 0;
43
  }
44
45
4748
  JSGraphJSNode(Isolate* isolate, Local<Value> val)
46
4748
      : persistent_(isolate, val) {
47
4748
    CHECK(!val.IsEmpty());
48
4748
  }
49
50
  struct Hash {
51
9496
    inline size_t operator()(JSGraphJSNode* n) const {
52
9496
      return static_cast<size_t>(n->IdentityHash());
53
    }
54
  };
55
56
  struct Equal {
57
    inline bool operator()(JSGraphJSNode* a, JSGraphJSNode* b) const {
58
      return a->JSValue()->SameValue(b->JSValue());
59
    }
60
  };
61
62
 private:
63
  Global<Value> persistent_;
64
};
65
66
16
class JSGraph : public EmbedderGraph {
67
 public:
68
16
  explicit JSGraph(Isolate* isolate) : isolate_(isolate) {}
69
70
4748
  Node* V8Node(const Local<Value>& value) override {
71
4748
    std::unique_ptr<JSGraphJSNode> n { new JSGraphJSNode(isolate_, value) };
72
4748
    auto it = engine_nodes_.find(n.get());
73
4748
    if (it != engine_nodes_.end())
74
      return *it;
75
4748
    engine_nodes_.insert(n.get());
76
4748
    return AddNode(std::unique_ptr<Node>(n.release()));
77
  }
78
79
6669
  Node* AddNode(std::unique_ptr<Node> node) override {
80
6669
    Node* n = node.get();
81
6669
    nodes_.emplace(std::move(node));
82
6669
    return n;
83
  }
84
85
6781
  void AddEdge(Node* from, Node* to, const char* name = nullptr) override {
86
6781
    edges_[from].insert(std::make_pair(name, to));
87
6781
  }
88
89
16
  MaybeLocal<Array> CreateObject() const {
90
16
    EscapableHandleScope handle_scope(isolate_);
91
16
    Local<Context> context = isolate_->GetCurrentContext();
92
93
32
    std::unordered_map<Node*, Local<Object>> info_objects;
94
16
    Local<Array> nodes = Array::New(isolate_, nodes_.size());
95
16
    Local<String> edges_string = FIXED_ONE_BYTE_STRING(isolate_, "edges");
96
16
    Local<String> is_root_string = FIXED_ONE_BYTE_STRING(isolate_, "isRoot");
97
16
    Local<String> name_string = FIXED_ONE_BYTE_STRING(isolate_, "name");
98
16
    Local<String> size_string = FIXED_ONE_BYTE_STRING(isolate_, "size");
99
16
    Local<String> value_string = FIXED_ONE_BYTE_STRING(isolate_, "value");
100
16
    Local<String> wraps_string = FIXED_ONE_BYTE_STRING(isolate_, "wraps");
101
16
    Local<String> to_string = FIXED_ONE_BYTE_STRING(isolate_, "to");
102
103
6685
    for (const std::unique_ptr<Node>& n : nodes_)
104
6669
      info_objects[n.get()] = Object::New(isolate_);
105
106
    {
107
16
      HandleScope handle_scope(isolate_);
108
16
      size_t i = 0;
109

6685
      for (const std::unique_ptr<Node>& n : nodes_) {
110
6669
        Local<Object> obj = info_objects[n.get()];
111
        Local<Value> value;
112
6669
        std::string name_str;
113
6669
        const char* prefix = n->NamePrefix();
114
6669
        if (prefix == nullptr) {
115
4748
          name_str = n->Name();
116
        } else {
117
1921
          name_str = n->NamePrefix();
118
1921
          name_str += " ";
119
1921
          name_str += n->Name();
120
        }
121
13338
        if (!String::NewFromUtf8(
122
6669
                 isolate_, name_str.c_str(), v8::NewStringType::kNormal)
123

40014
                 .ToLocal(&value) ||
124

40014
            obj->Set(context, name_string, value).IsNothing() ||
125
            obj->Set(context,
126
                     is_root_string,
127

20007
                     Boolean::New(isolate_, n->IsRootNode()))
128

46683
                .IsNothing() ||
129
            obj->Set(context,
130
                     size_string,
131

20007
                     Number::New(isolate_, n->SizeInBytes()))
132

66690
                .IsNothing() ||
133

40014
            obj->Set(context, edges_string, Array::New(isolate_)).IsNothing()) {
134
          return MaybeLocal<Array>();
135
        }
136
20007
        if (nodes->Set(context, i++, obj).IsNothing())
137
          return MaybeLocal<Array>();
138
6669
        if (!n->IsEmbedderNode()) {
139
4748
          value = static_cast<JSGraphJSNode*>(n.get())->JSValue();
140
9496
          if (obj->Set(context, value_string, value).IsNothing())
141
            return MaybeLocal<Array>();
142
        }
143
6685
      }
144
    }
145
146
6685
    for (const std::unique_ptr<Node>& n : nodes_) {
147
6669
      Node* wraps = n->WrapperNode();
148
6669
      if (wraps == nullptr) continue;
149
      Local<Object> from = info_objects[n.get()];
150
      Local<Object> to = info_objects[wraps];
151
      if (from->Set(context, wraps_string, to).IsNothing())
152
        return MaybeLocal<Array>();
153
    }
154
155
567
    for (const auto& edge_info : edges_) {
156
551
      Node* source = edge_info.first;
157
      Local<Value> edges;
158


2755
      if (!info_objects[source]->Get(context, edges_string).ToLocal(&edges) ||
159
551
          !edges->IsArray()) {
160
        return MaybeLocal<Array>();
161
      }
162
163
551
      size_t i = 0;
164
551
      size_t j = 0;
165
7332
      for (const auto& edge : edge_info.second) {
166
6781
        Local<Object> to_object = info_objects[edge.second];
167
6781
        Local<Object> edge_obj = Object::New(isolate_);
168
        Local<Value> edge_name_value;
169
6781
        const char* edge_name = edge.first;
170
6781
        if (edge_name != nullptr) {
171
9072
          if (!String::NewFromUtf8(
172
4536
                  isolate_, edge_name, v8::NewStringType::kNormal)
173
13608
                  .ToLocal(&edge_name_value)) {
174
            return MaybeLocal<Array>();
175
          }
176
        } else {
177
4490
          edge_name_value = Number::New(isolate_, j++);
178
        }
179


47467
        if (edge_obj->Set(context, name_string, edge_name_value).IsNothing() ||
180


67810
            edge_obj->Set(context, to_string, to_object).IsNothing() ||
181

33905
            edges.As<Array>()->Set(context, i++, edge_obj).IsNothing()) {
182
          return MaybeLocal<Array>();
183
        }
184
      }
185
    }
186
187
16
    return handle_scope.Escape(nodes);
188
  }
189
190
 private:
191
  Isolate* isolate_;
192
  std::unordered_set<std::unique_ptr<Node>> nodes_;
193
  std::unordered_set<JSGraphJSNode*, JSGraphJSNode::Hash, JSGraphJSNode::Equal>
194
      engine_nodes_;
195
  std::unordered_map<Node*, std::set<std::pair<const char*, Node*>>> edges_;
196
};
197
198
16
void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
199
16
  Environment* env = Environment::GetCurrent(args);
200
16
  JSGraph graph(env->isolate());
201
16
  Environment::BuildEmbedderGraph(env->isolate(), &graph, env);
202
  Local<Array> ret;
203
32
  if (graph.CreateObject().ToLocal(&ret))
204
32
    args.GetReturnValue().Set(ret);
205
16
}
206
207
namespace {
208
4
class FileOutputStream : public v8::OutputStream {
209
 public:
210
4
  explicit FileOutputStream(FILE* stream) : stream_(stream) {}
211
212
8
  int GetChunkSize() override {
213
8
    return 65536;  // big chunks == faster
214
  }
215
216
4
  void EndOfStream() override {}
217
218
186
  WriteResult WriteAsciiChunk(char* data, int size) override {
219
186
    const size_t len = static_cast<size_t>(size);
220
186
    size_t off = 0;
221
222


558
    while (off < len && !feof(stream_) && !ferror(stream_))
223
186
      off += fwrite(data + off, 1, len - off, stream_);
224
225
186
    return off == len ? kContinue : kAbort;
226
  }
227
228
 private:
229
  FILE* stream_;
230
};
231
232
class HeapSnapshotStream : public AsyncWrap,
233
                           public StreamBase,
234
                           public v8::OutputStream {
235
 public:
236
28
  HeapSnapshotStream(
237
      Environment* env,
238
      const HeapSnapshot* snapshot,
239
      v8::Local<v8::Object> obj) :
240
      AsyncWrap(env, obj, AsyncWrap::PROVIDER_HEAPSNAPSHOT),
241
      StreamBase(env),
242
28
      snapshot_(snapshot) {
243
28
    MakeWeak();
244
28
    StreamBase::AttachToObject(GetObject());
245
28
  }
246
247
81
  ~HeapSnapshotStream() override {
248
27
    Cleanup();
249
54
  }
250
251
54
  int GetChunkSize() override {
252
54
    return 65536;  // big chunks == faster
253
  }
254
255
27
  void EndOfStream() override {
256
27
    EmitRead(UV_EOF);
257
27
    Cleanup();
258
27
  }
259
260
1348
  WriteResult WriteAsciiChunk(char* data, int size) override {
261
1348
    int len = size;
262
4044
    while (len != 0) {
263
1348
      uv_buf_t buf = EmitAlloc(size);
264
1348
      ssize_t avail = len;
265
1348
      if (static_cast<ssize_t>(buf.len) < avail)
266
        avail = buf.len;
267
1348
      memcpy(buf.base, data, avail);
268
1348
      data += avail;
269
1348
      len -= avail;
270
1348
      EmitRead(size, buf);
271
    }
272
1348
    return kContinue;
273
  }
274
275
27
  int ReadStart() override {
276
27
    CHECK_NE(snapshot_, nullptr);
277
27
    snapshot_->Serialize(this, HeapSnapshot::kJSON);
278
27
    return 0;
279
  }
280
281
1348
  int ReadStop() override {
282
1348
    return 0;
283
  }
284
285
  int DoShutdown(ShutdownWrap* req_wrap) override {
286
    UNREACHABLE();
287
  }
288
289
  int DoWrite(WriteWrap* w,
290
              uv_buf_t* bufs,
291
              size_t count,
292
              uv_stream_t* send_handle) override {
293
    UNREACHABLE();
294
  }
295
296
1375
  bool IsAlive() override { return snapshot_ != nullptr; }
297
  bool IsClosing() override { return snapshot_ == nullptr; }
298
2778
  AsyncWrap* GetAsyncWrap() override { return this; }
299
300
39
  void MemoryInfo(MemoryTracker* tracker) const override {
301
39
    if (snapshot_ != nullptr) {
302
      tracker->TrackFieldWithSize(
303
7
          "snapshot", sizeof(*snapshot_), "HeapSnapshot");
304
    }
305
39
  }
306
307
39
  SET_MEMORY_INFO_NAME(HeapSnapshotStream)
308
39
  SET_SELF_SIZE(HeapSnapshotStream)
309
310
 private:
311
54
  void Cleanup() {
312
54
    if (snapshot_ != nullptr) {
313
28
      const_cast<HeapSnapshot*>(snapshot_)->Delete();
314
28
      snapshot_ = nullptr;
315
    }
316
54
  }
317
318
319
  const HeapSnapshot* snapshot_;
320
};
321
322
4
inline void TakeSnapshot(Isolate* isolate, v8::OutputStream* out) {
323
  const HeapSnapshot* const snapshot =
324
4
      isolate->GetHeapProfiler()->TakeHeapSnapshot();
325
4
  snapshot->Serialize(out, HeapSnapshot::kJSON);
326
4
  const_cast<HeapSnapshot*>(snapshot)->Delete();
327
4
}
328
329
4
inline bool WriteSnapshot(Isolate* isolate, const char* filename) {
330
4
  FILE* fp = fopen(filename, "w");
331
4
  if (fp == nullptr)
332
    return false;
333
4
  FileOutputStream stream(fp);
334
4
  TakeSnapshot(isolate, &stream);
335
4
  fclose(fp);
336
4
  return true;
337
}
338
339
}  // namespace
340
341
28
void CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) {
342
28
  Environment* env = Environment::GetCurrent(args);
343
28
  HandleScope scope(env->isolate());
344
  const HeapSnapshot* const snapshot =
345
28
      env->isolate()->GetHeapProfiler()->TakeHeapSnapshot();
346
28
  CHECK_NOT_NULL(snapshot);
347
  Local<Object> obj;
348
56
  if (!env->streambaseoutputstream_constructor_template()
349
84
           ->NewInstance(env->context())
350
84
           .ToLocal(&obj)) {
351
28
    return;
352
  }
353
28
  HeapSnapshotStream* out = new HeapSnapshotStream(env, snapshot, obj);
354
84
  args.GetReturnValue().Set(out->object());
355
}
356
357
4
void TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) {
358
4
  Environment* env = Environment::GetCurrent(args);
359
4
  Isolate* isolate = args.GetIsolate();
360
361
4
  Local<Value> filename_v = args[0];
362
363
8
  if (filename_v->IsUndefined()) {
364
3
    DiagnosticFilename name(env, "Heap", "heapsnapshot");
365
3
    if (!WriteSnapshot(isolate, *name))
366
      return;
367
9
    if (String::NewFromUtf8(isolate, *name, v8::NewStringType::kNormal)
368
6
            .ToLocal(&filename_v)) {
369
6
      args.GetReturnValue().Set(filename_v);
370
    }
371
3
    return;
372
  }
373
374
1
  BufferValue path(isolate, filename_v);
375
1
  CHECK_NOT_NULL(*path);
376
1
  if (!WriteSnapshot(isolate, *path))
377
    return;
378
2
  return args.GetReturnValue().Set(filename_v);
379
}
380
381
66
void Initialize(Local<Object> target,
382
                Local<Value> unused,
383
                Local<Context> context,
384
                void* priv) {
385
66
  Environment* env = Environment::GetCurrent(context);
386
387
  env->SetMethodNoSideEffect(target,
388
                             "buildEmbedderGraph",
389
66
                             BuildEmbedderGraph);
390
  env->SetMethodNoSideEffect(target,
391
                             "triggerHeapSnapshot",
392
66
                             TriggerHeapSnapshot);
393
  env->SetMethodNoSideEffect(target,
394
                             "createHeapSnapshotStream",
395
66
                             CreateHeapSnapshotStream);
396
397
  // Create FunctionTemplate for HeapSnapshotStream
398
66
  Local<FunctionTemplate> os = FunctionTemplate::New(env->isolate());
399
132
  os->Inherit(AsyncWrap::GetConstructorTemplate(env));
400
66
  Local<ObjectTemplate> ost = os->InstanceTemplate();
401
66
  ost->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
402
132
  os->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HeapSnapshotStream"));
403
66
  StreamBase::AddMethods(env, os);
404
66
  env->set_streambaseoutputstream_constructor_template(ost);
405
66
}
406
407
}  // namespace heap
408
}  // namespace node
409
410
4827
NODE_MODULE_CONTEXT_AWARE_INTERNAL(heap_utils, node::heap::Initialize)