7
7
8
8
namespace node {
9
9
10
+ class MemoryRetainerNode : public v8 ::EmbedderGraph::Node {
11
+ public:
12
+ explicit inline MemoryRetainerNode (MemoryTracker* tracker,
13
+ const MemoryRetainer* retainer,
14
+ const char * name)
15
+ : retainer_(retainer) {
16
+ if (retainer_ != nullptr ) {
17
+ v8::HandleScope handle_scope (tracker->isolate ());
18
+ v8::Local<v8::Object> obj = retainer_->WrappedObject ();
19
+ if (!obj.IsEmpty ())
20
+ wrapper_node_ = tracker->graph ()->V8Node (obj);
21
+
22
+ name_ = retainer_->MemoryInfoName ();
23
+ }
24
+ if (name_.empty () && name != nullptr ) {
25
+ name_ = name;
26
+ }
27
+ }
28
+
29
+ const char * Name () override { return name_.c_str (); }
30
+ const char * NamePrefix () override { return " Node /" ; }
31
+ size_t SizeInBytes () override { return size_; }
32
+ // TODO(addaleax): Merging this with the "official" WrapperNode() method
33
+ // seems to lose accuracy, e.g. SizeInBytes() is disregarded.
34
+ // Figure out whether to do anything about that.
35
+ Node* JSWrapperNode () { return wrapper_node_; }
36
+
37
+ bool IsRootNode () override {
38
+ return retainer_ != nullptr && retainer_->IsRootNode ();
39
+ }
40
+
41
+ private:
42
+ friend class MemoryTracker ;
43
+
44
+ Node* wrapper_node_ = nullptr ;
45
+ const MemoryRetainer* retainer_;
46
+ std::string name_;
47
+ size_t size_ = 0 ;
48
+ };
49
+
10
50
template <typename T>
11
51
void MemoryTracker::TrackThis (const T* obj) {
12
- accumulated_size_ + = sizeof (T);
52
+ CurrentNode ()-> size_ = sizeof (T);
13
53
}
14
54
15
55
void MemoryTracker::TrackFieldWithSize (const char * name, size_t size) {
16
- accumulated_size_ += size;
56
+ if (size > 0 )
57
+ AddNode (name)->size_ = size;
17
58
}
18
59
19
60
void MemoryTracker::TrackField (const char * name, const MemoryRetainer& value) {
20
61
TrackField (name, &value);
21
62
}
22
63
23
64
void MemoryTracker::TrackField (const char * name, const MemoryRetainer* value) {
24
- if (track_only_self_ || value == nullptr || seen_.count (value) > 0 ) return ;
25
- seen_.insert (value);
26
- Track (value);
65
+ if (track_only_self_ || value == nullptr ) return ;
66
+ auto it = seen_.find (value);
67
+ if (it != seen_.end ()) {
68
+ graph_->AddEdge (CurrentNode (), it->second );
69
+ } else {
70
+ Track (value, name);
71
+ }
27
72
}
28
73
29
74
template <typename T>
@@ -36,8 +81,10 @@ template <typename T, typename Iterator>
36
81
void MemoryTracker::TrackField (const char * name, const T& value) {
37
82
if (value.begin () == value.end ()) return ;
38
83
size_t index = 0 ;
84
+ PushNode (name);
39
85
for (Iterator it = value.begin (); it != value.end (); ++it)
40
86
TrackField (std::to_string (index ++).c_str (), *it);
87
+ PopNode ();
41
88
}
42
89
43
90
template <typename T>
@@ -56,13 +103,15 @@ void MemoryTracker::TrackField(const char* name, const std::queue<T>& value) {
56
103
template <typename T, typename test_for_number, typename dummy>
57
104
void MemoryTracker::TrackField (const char * name, const T& value) {
58
105
// For numbers, creating new nodes is not worth the overhead.
59
- TrackFieldWithSize (name, sizeof (T) );
106
+ CurrentNode ()-> size_ += sizeof (T);
60
107
}
61
108
62
109
template <typename T, typename U>
63
110
void MemoryTracker::TrackField (const char * name, const std::pair<T, U>& value) {
111
+ PushNode (name);
64
112
TrackField (" first" , value.first );
65
113
TrackField (" second" , value.second );
114
+ PopNode ();
66
115
}
67
116
68
117
template <typename T>
@@ -74,10 +123,13 @@ void MemoryTracker::TrackField(const char* name,
74
123
template <typename T, typename Traits>
75
124
void MemoryTracker::TrackField (const char * name,
76
125
const v8::Persistent<T, Traits>& value) {
126
+ TrackField (name, value.Get (isolate_));
77
127
}
78
128
79
129
template <typename T>
80
130
void MemoryTracker::TrackField (const char * name, const v8::Local<T>& value) {
131
+ if (!value.IsEmpty ())
132
+ graph_->AddEdge (CurrentNode (), graph_->V8Node (value));
81
133
}
82
134
83
135
template <typename T>
@@ -96,8 +148,47 @@ void MemoryTracker::TrackField(const char* name,
96
148
TrackField (name, value.GetJSArray ());
97
149
}
98
150
99
- void MemoryTracker::Track (const MemoryRetainer* value) {
151
+ void MemoryTracker::Track (const MemoryRetainer* value, const char * name) {
152
+ v8::HandleScope handle_scope (isolate_);
153
+ MemoryRetainerNode* n = PushNode (name, value);
100
154
value->MemoryInfo (this );
155
+ CHECK_EQ (CurrentNode (), n);
156
+ CHECK_NE (n->size_ , 0 );
157
+ PopNode ();
158
+ }
159
+
160
+ MemoryRetainerNode* MemoryTracker::CurrentNode () const {
161
+ if (node_stack_.empty ()) return nullptr ;
162
+ return node_stack_.top ();
163
+ }
164
+
165
+ MemoryRetainerNode* MemoryTracker::AddNode (
166
+ const char * name, const MemoryRetainer* retainer) {
167
+ MemoryRetainerNode* n = new MemoryRetainerNode (this , retainer, name);
168
+ graph_->AddNode (std::unique_ptr<v8::EmbedderGraph::Node>(n));
169
+ if (retainer != nullptr )
170
+ seen_[retainer] = n;
171
+
172
+ if (CurrentNode () != nullptr )
173
+ graph_->AddEdge (CurrentNode (), n);
174
+
175
+ if (n->JSWrapperNode () != nullptr ) {
176
+ graph_->AddEdge (n, n->JSWrapperNode ());
177
+ graph_->AddEdge (n->JSWrapperNode (), n);
178
+ }
179
+
180
+ return n;
181
+ }
182
+
183
+ MemoryRetainerNode* MemoryTracker::PushNode (
184
+ const char * name, const MemoryRetainer* retainer) {
185
+ MemoryRetainerNode* n = AddNode (name, retainer);
186
+ node_stack_.push (n);
187
+ return n;
188
+ }
189
+
190
+ void MemoryTracker::PopNode () {
191
+ node_stack_.pop ();
101
192
}
102
193
103
194
} // namespace node
0 commit comments