Skip to content

Commit 316ac8c

Browse files
authored
src: add memory retainer traits for external types
Add `MemoryRetainerTraits` to reveal external type memory info without forcing them to inherit from `MemoryRetainer`. PR-URL: #56881 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent c889b85 commit 316ac8c

File tree

4 files changed

+123
-7
lines changed

4 files changed

+123
-7
lines changed

src/memory_tracker-inl.h

+21
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,27 @@ void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer,
297297
CurrentNode()->size_ -= retainer->SelfSize();
298298
}
299299

300+
template <typename T>
301+
inline void MemoryTracker::TraitTrack(const T& retainer,
302+
const char* edge_name) {
303+
MemoryRetainerNode* n =
304+
PushNode(MemoryRetainerTraits<T>::MemoryInfoName(retainer),
305+
MemoryRetainerTraits<T>::SelfSize(retainer),
306+
edge_name);
307+
MemoryRetainerTraits<T>::MemoryInfo(this, retainer);
308+
CHECK_EQ(CurrentNode(), n);
309+
CHECK_NE(n->size_, 0);
310+
PopNode();
311+
}
312+
313+
template <typename T>
314+
inline void MemoryTracker::TraitTrackInline(const T& retainer,
315+
const char* edge_name) {
316+
TraitTrack(retainer, edge_name);
317+
CHECK(CurrentNode());
318+
CurrentNode()->size_ -= MemoryRetainerTraits<T>::SelfSize(retainer);
319+
}
320+
300321
MemoryRetainerNode* MemoryTracker::CurrentNode() const {
301322
if (node_stack_.empty()) return nullptr;
302323
return node_stack_.top();

src/memory_tracker.h

+34
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ class MemoryRetainer {
138138
}
139139
};
140140

141+
/**
142+
* MemoryRetainerTraits allows defining a custom memory info for a
143+
* class that can not be modified to implement the MemoryRetainer interface.
144+
*
145+
* Example:
146+
*
147+
* template <>
148+
* struct MemoryRetainerTraits<ExampleRetainer> {
149+
* static void MemoryInfo(MemoryTracker* tracker,
150+
* const ExampleRetainer& value) {
151+
* tracker->TrackField("another_retainer", value.another_retainer_);
152+
* }
153+
* static const char* MemoryInfoName(const ExampleRetainer& value) {
154+
* return "ExampleRetainer";
155+
* }
156+
* static size_t SelfSize(const ExampleRetainer& value) {
157+
* return sizeof(value);
158+
* }
159+
* };
160+
*
161+
* This creates the following graph:
162+
* Node / ExampleRetainer
163+
* |> another_retainer :: Node / AnotherRetainerClass
164+
*/
165+
template <typename T, typename = void>
166+
struct MemoryRetainerTraits {};
167+
141168
class MemoryTracker {
142169
public:
143170
// Used to specify node name and size explicitly
@@ -254,6 +281,13 @@ class MemoryTracker {
254281
inline void TrackInlineField(const MemoryRetainer* retainer,
255282
const char* edge_name = nullptr);
256283

284+
// MemoryRetainerTraits implementation helpers.
285+
template <typename T>
286+
inline void TraitTrack(const T& retainer, const char* edge_name = nullptr);
287+
template <typename T>
288+
inline void TraitTrackInline(const T& retainer,
289+
const char* edge_name = nullptr);
290+
257291
inline v8::EmbedderGraph* graph() { return graph_; }
258292
inline v8::Isolate* isolate() { return isolate_; }
259293

src/node_url_pattern.cc

+43-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,48 @@
88
#include "path.h"
99
#include "util-inl.h"
1010

11+
namespace node {
12+
using node::url_pattern::URLPatternRegexProvider;
13+
14+
template <>
15+
struct MemoryRetainerTraits<ada::url_pattern<URLPatternRegexProvider>> {
16+
using Type = ada::url_pattern<URLPatternRegexProvider>;
17+
static void MemoryInfo(MemoryTracker* tracker, const Type& value) {
18+
tracker->TraitTrackInline(value.protocol_component, "protocol_component");
19+
tracker->TraitTrackInline(value.username_component, "username_component");
20+
tracker->TraitTrackInline(value.password_component, "password_component");
21+
tracker->TraitTrackInline(value.hostname_component, "hostname_component");
22+
tracker->TraitTrackInline(value.port_component, "port_component");
23+
tracker->TraitTrackInline(value.pathname_component, "pathname_component");
24+
tracker->TraitTrackInline(value.search_component, "search_component");
25+
tracker->TraitTrackInline(value.hash_component, "hash_component");
26+
}
27+
28+
static const char* MemoryInfoName(const Type& value) {
29+
return "ada::url_pattern";
30+
}
31+
32+
static size_t SelfSize(const Type& value) { return sizeof(value); }
33+
};
34+
35+
template <>
36+
struct MemoryRetainerTraits<
37+
ada::url_pattern_component<URLPatternRegexProvider>> {
38+
using Type = ada::url_pattern_component<URLPatternRegexProvider>;
39+
static void MemoryInfo(MemoryTracker* tracker, const Type& value) {
40+
tracker->TrackField("pattern", value.pattern);
41+
tracker->TrackField("group_name_list", value.group_name_list);
42+
}
43+
44+
static const char* MemoryInfoName(const Type& value) {
45+
return "ada::url_pattern_component";
46+
}
47+
48+
static size_t SelfSize(const Type& value) { return sizeof(value); }
49+
};
50+
51+
} // namespace node
52+
1153
namespace node::url_pattern {
1254

1355
using v8::Array;
@@ -125,13 +167,7 @@ URLPattern::URLPattern(Environment* env,
125167
}
126168

127169
void URLPattern::MemoryInfo(MemoryTracker* tracker) const {
128-
tracker->TrackFieldWithSize("protocol", url_pattern_.get_protocol().size());
129-
tracker->TrackFieldWithSize("username", url_pattern_.get_username().size());
130-
tracker->TrackFieldWithSize("password", url_pattern_.get_password().size());
131-
tracker->TrackFieldWithSize("hostname", url_pattern_.get_hostname().size());
132-
tracker->TrackFieldWithSize("pathname", url_pattern_.get_pathname().size());
133-
tracker->TrackFieldWithSize("search", url_pattern_.get_search().size());
134-
tracker->TrackFieldWithSize("hash", url_pattern_.get_hash().size());
170+
tracker->TraitTrackInline(url_pattern_, "url_pattern");
135171
}
136172

137173
void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
require('../common');
4+
const { validateSnapshotNodes } = require('../common/heap');
5+
const { URLPattern } = require('node:url');
6+
7+
validateSnapshotNodes('Node / URLPattern', []);
8+
const urlPattern = new URLPattern('https://example.com/:id');
9+
validateSnapshotNodes('Node / URLPattern', [
10+
{
11+
children: [
12+
{ node_name: 'Node / ada::url_pattern', edge_name: 'url_pattern' },
13+
],
14+
},
15+
]);
16+
validateSnapshotNodes('Node / ada::url_pattern', [
17+
{
18+
children: [
19+
{ node_name: 'Node / ada::url_pattern_component', edge_name: 'protocol_component' },
20+
],
21+
},
22+
]);
23+
24+
// Use `urlPattern`.
25+
console.log(urlPattern);

0 commit comments

Comments
 (0)