GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/heap_utils.cc Lines: 129 145 89.0 %
Date: 2019-01-07 12:15:22 Branches: 66 122 54.1 %

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

112
      for (const std::unique_ptr<Node>& n : nodes_) {
104
96
        Local<Object> obj = info_objects[n.get()];
105
        Local<Value> value;
106
96
        std::string name_str;
107
96
        const char* prefix = n->NamePrefix();
108
96
        if (prefix == nullptr) {
109
34
          name_str = n->Name();
110
        } else {
111
62
          name_str = n->NamePrefix();
112
62
          name_str += " ";
113
62
          name_str += n->Name();
114
        }
115
192
        if (!String::NewFromUtf8(
116
96
                 isolate_, name_str.c_str(), v8::NewStringType::kNormal)
117

576
                 .ToLocal(&value) ||
118

576
            obj->Set(context, name_string, value).IsNothing() ||
119
            obj->Set(context,
120
                     is_root_string,
121

288
                     Boolean::New(isolate_, n->IsRootNode()))
122

672
                .IsNothing() ||
123
            obj->Set(context,
124
                     size_string,
125

288
                     Number::New(isolate_, n->SizeInBytes()))
126

960
                .IsNothing() ||
127

576
            obj->Set(context, edges_string, Array::New(isolate_)).IsNothing()) {
128
          return MaybeLocal<Array>();
129
        }
130
288
        if (nodes->Set(context, i++, obj).IsNothing())
131
          return MaybeLocal<Array>();
132
96
        if (!n->IsEmbedderNode()) {
133
34
          value = static_cast<JSGraphJSNode*>(n.get())->JSValue();
134
68
          if (obj->Set(context, value_string, value).IsNothing())
135
            return MaybeLocal<Array>();
136
        }
137
112
      }
138
    }
139
140
112
    for (const std::unique_ptr<Node>& n : nodes_) {
141
96
      Node* wraps = n->WrapperNode();
142
96
      if (wraps == nullptr) continue;
143
      Local<Object> from = info_objects[n.get()];
144
      Local<Object> to = info_objects[wraps];
145
      if (from->Set(context, wraps_string, to).IsNothing())
146
        return MaybeLocal<Array>();
147
    }
148
149
92
    for (const auto& edge_info : edges_) {
150
76
      Node* source = edge_info.first;
151
      Local<Value> edges;
152


380
      if (!info_objects[source]->Get(context, edges_string).ToLocal(&edges) ||
153
76
          !edges->IsArray()) {
154
        return MaybeLocal<Array>();
155
      }
156
157
76
      size_t i = 0;
158
76
      size_t j = 0;
159
179
      for (const auto& edge : edge_info.second) {
160
103
        Local<Object> to_object = info_objects[edge.second];
161
103
        Local<Object> edge_obj = Object::New(isolate_);
162
        Local<Value> edge_name_value;
163
103
        const char* edge_name = edge.first;
164
103
        if (edge_name != nullptr) {
165
194
          if (!String::NewFromUtf8(
166
97
                  isolate_, edge_name, v8::NewStringType::kNormal)
167
291
                  .ToLocal(&edge_name_value)) {
168
            return MaybeLocal<Array>();
169
          }
170
        } else {
171
12
          edge_name_value = Number::New(isolate_, j++);
172
        }
173


721
        if (edge_obj->Set(context, name_string, edge_name_value).IsNothing() ||
174


1030
            edge_obj->Set(context, to_string, to_object).IsNothing() ||
175

515
            edges.As<Array>()->Set(context, i++, edge_obj).IsNothing()) {
176
          return MaybeLocal<Array>();
177
        }
178
      }
179
    }
180
181
16
    return handle_scope.Escape(nodes);
182
  }
183
184
 private:
185
  Isolate* isolate_;
186
  std::unordered_set<std::unique_ptr<Node>> nodes_;
187
  std::unordered_set<JSGraphJSNode*, JSGraphJSNode::Hash, JSGraphJSNode::Equal>
188
      engine_nodes_;
189
  std::unordered_map<Node*, std::set<std::pair<const char*, Node*>>> edges_;
190
};
191
192
16
void BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) {
193
16
  Environment* env = Environment::GetCurrent(args);
194
16
  JSGraph graph(env->isolate());
195
16
  Environment::BuildEmbedderGraph(env->isolate(), &graph, env);
196
  Local<Array> ret;
197
32
  if (graph.CreateObject().ToLocal(&ret))
198
32
    args.GetReturnValue().Set(ret);
199
16
}
200
201
202
16
class BufferOutputStream : public v8::OutputStream {
203
 public:
204
16
  BufferOutputStream() : buffer_(new JSString()) {}
205
206
16
  void EndOfStream() override {}
207
32
  int GetChunkSize() override { return 1024 * 1024; }
208
181
  WriteResult WriteAsciiChunk(char* data, int size) override {
209
181
    buffer_->Append(data, size);
210
181
    return kContinue;
211
  }
212
213
16
  Local<String> ToString(Isolate* isolate) {
214
    return String::NewExternalOneByte(isolate,
215
32
                                      buffer_.release()).ToLocalChecked();
216
  }
217
218
 private:
219
48
  class JSString : public String::ExternalOneByteStringResource {
220
   public:
221
181
    void Append(char* data, size_t count) {
222
181
      store_.append(data, count);
223
181
    }
224
225
183082388
    const char* data() const override { return store_.data(); }
226
64
    size_t length() const override { return store_.size(); }
227
228
   private:
229
    std::string store_;
230
  };
231
232
  std::unique_ptr<JSString> buffer_;
233
};
234
235
16
void CreateHeapDump(const FunctionCallbackInfo<Value>& args) {
236
16
  Isolate* isolate = args.GetIsolate();
237
16
  const HeapSnapshot* snapshot = isolate->GetHeapProfiler()->TakeHeapSnapshot();
238
16
  BufferOutputStream out;
239
16
  snapshot->Serialize(&out, HeapSnapshot::kJSON);
240
16
  const_cast<HeapSnapshot*>(snapshot)->Delete();
241
  Local<Value> ret;
242
32
  if (JSON::Parse(isolate->GetCurrentContext(),
243
32
                  out.ToString(isolate)).ToLocal(&ret)) {
244
32
    args.GetReturnValue().Set(ret);
245
16
  }
246
16
}
247
248
8
void Initialize(Local<Object> target,
249
                Local<Value> unused,
250
                Local<Context> context,
251
                void* priv) {
252
8
  Environment* env = Environment::GetCurrent(context);
253
254
8
  env->SetMethodNoSideEffect(target, "buildEmbedderGraph", BuildEmbedderGraph);
255
8
  env->SetMethodNoSideEffect(target, "createHeapDump", CreateHeapDump);
256
8
}
257
258
}  // namespace heap
259
}  // namespace node
260
261
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(heap_utils, node::heap::Initialize)