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: 129 145 89.0 %
Date: 2019-02-23 22:23:05 Branches: 66 122 54.1 %

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

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

822
                 .ToLocal(&value) ||
117

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

411
                     Boolean::New(isolate_, n->IsRootNode()))
121

959
                .IsNothing() ||
122
            obj->Set(context,
123
                     size_string,
124

411
                     Number::New(isolate_, n->SizeInBytes()))
125

1370
                .IsNothing() ||
126

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


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


1008
        if (edge_obj->Set(context, name_string, edge_name_value).IsNothing() ||
173


1440
            edge_obj->Set(context, to_string, to_object).IsNothing() ||
174

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