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: https://github.com/nodejs/node/pull/56881 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
c889b85498
commit
316ac8c250
@ -297,6 +297,27 @@ void MemoryTracker::TrackInlineField(const MemoryRetainer* retainer,
|
|||||||
CurrentNode()->size_ -= retainer->SelfSize();
|
CurrentNode()->size_ -= retainer->SelfSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void MemoryTracker::TraitTrack(const T& retainer,
|
||||||
|
const char* edge_name) {
|
||||||
|
MemoryRetainerNode* n =
|
||||||
|
PushNode(MemoryRetainerTraits<T>::MemoryInfoName(retainer),
|
||||||
|
MemoryRetainerTraits<T>::SelfSize(retainer),
|
||||||
|
edge_name);
|
||||||
|
MemoryRetainerTraits<T>::MemoryInfo(this, retainer);
|
||||||
|
CHECK_EQ(CurrentNode(), n);
|
||||||
|
CHECK_NE(n->size_, 0);
|
||||||
|
PopNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void MemoryTracker::TraitTrackInline(const T& retainer,
|
||||||
|
const char* edge_name) {
|
||||||
|
TraitTrack(retainer, edge_name);
|
||||||
|
CHECK(CurrentNode());
|
||||||
|
CurrentNode()->size_ -= MemoryRetainerTraits<T>::SelfSize(retainer);
|
||||||
|
}
|
||||||
|
|
||||||
MemoryRetainerNode* MemoryTracker::CurrentNode() const {
|
MemoryRetainerNode* MemoryTracker::CurrentNode() const {
|
||||||
if (node_stack_.empty()) return nullptr;
|
if (node_stack_.empty()) return nullptr;
|
||||||
return node_stack_.top();
|
return node_stack_.top();
|
||||||
|
@ -138,6 +138,33 @@ class MemoryRetainer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MemoryRetainerTraits allows defining a custom memory info for a
|
||||||
|
* class that can not be modified to implement the MemoryRetainer interface.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* template <>
|
||||||
|
* struct MemoryRetainerTraits<ExampleRetainer> {
|
||||||
|
* static void MemoryInfo(MemoryTracker* tracker,
|
||||||
|
* const ExampleRetainer& value) {
|
||||||
|
* tracker->TrackField("another_retainer", value.another_retainer_);
|
||||||
|
* }
|
||||||
|
* static const char* MemoryInfoName(const ExampleRetainer& value) {
|
||||||
|
* return "ExampleRetainer";
|
||||||
|
* }
|
||||||
|
* static size_t SelfSize(const ExampleRetainer& value) {
|
||||||
|
* return sizeof(value);
|
||||||
|
* }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* This creates the following graph:
|
||||||
|
* Node / ExampleRetainer
|
||||||
|
* |> another_retainer :: Node / AnotherRetainerClass
|
||||||
|
*/
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct MemoryRetainerTraits {};
|
||||||
|
|
||||||
class MemoryTracker {
|
class MemoryTracker {
|
||||||
public:
|
public:
|
||||||
// Used to specify node name and size explicitly
|
// Used to specify node name and size explicitly
|
||||||
@ -254,6 +281,13 @@ class MemoryTracker {
|
|||||||
inline void TrackInlineField(const MemoryRetainer* retainer,
|
inline void TrackInlineField(const MemoryRetainer* retainer,
|
||||||
const char* edge_name = nullptr);
|
const char* edge_name = nullptr);
|
||||||
|
|
||||||
|
// MemoryRetainerTraits implementation helpers.
|
||||||
|
template <typename T>
|
||||||
|
inline void TraitTrack(const T& retainer, const char* edge_name = nullptr);
|
||||||
|
template <typename T>
|
||||||
|
inline void TraitTrackInline(const T& retainer,
|
||||||
|
const char* edge_name = nullptr);
|
||||||
|
|
||||||
inline v8::EmbedderGraph* graph() { return graph_; }
|
inline v8::EmbedderGraph* graph() { return graph_; }
|
||||||
inline v8::Isolate* isolate() { return isolate_; }
|
inline v8::Isolate* isolate() { return isolate_; }
|
||||||
|
|
||||||
|
@ -8,6 +8,48 @@
|
|||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "util-inl.h"
|
#include "util-inl.h"
|
||||||
|
|
||||||
|
namespace node {
|
||||||
|
using node::url_pattern::URLPatternRegexProvider;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MemoryRetainerTraits<ada::url_pattern<URLPatternRegexProvider>> {
|
||||||
|
using Type = ada::url_pattern<URLPatternRegexProvider>;
|
||||||
|
static void MemoryInfo(MemoryTracker* tracker, const Type& value) {
|
||||||
|
tracker->TraitTrackInline(value.protocol_component, "protocol_component");
|
||||||
|
tracker->TraitTrackInline(value.username_component, "username_component");
|
||||||
|
tracker->TraitTrackInline(value.password_component, "password_component");
|
||||||
|
tracker->TraitTrackInline(value.hostname_component, "hostname_component");
|
||||||
|
tracker->TraitTrackInline(value.port_component, "port_component");
|
||||||
|
tracker->TraitTrackInline(value.pathname_component, "pathname_component");
|
||||||
|
tracker->TraitTrackInline(value.search_component, "search_component");
|
||||||
|
tracker->TraitTrackInline(value.hash_component, "hash_component");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* MemoryInfoName(const Type& value) {
|
||||||
|
return "ada::url_pattern";
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t SelfSize(const Type& value) { return sizeof(value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MemoryRetainerTraits<
|
||||||
|
ada::url_pattern_component<URLPatternRegexProvider>> {
|
||||||
|
using Type = ada::url_pattern_component<URLPatternRegexProvider>;
|
||||||
|
static void MemoryInfo(MemoryTracker* tracker, const Type& value) {
|
||||||
|
tracker->TrackField("pattern", value.pattern);
|
||||||
|
tracker->TrackField("group_name_list", value.group_name_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* MemoryInfoName(const Type& value) {
|
||||||
|
return "ada::url_pattern_component";
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t SelfSize(const Type& value) { return sizeof(value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace node
|
||||||
|
|
||||||
namespace node::url_pattern {
|
namespace node::url_pattern {
|
||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
@ -125,13 +167,7 @@ URLPattern::URLPattern(Environment* env,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void URLPattern::MemoryInfo(MemoryTracker* tracker) const {
|
void URLPattern::MemoryInfo(MemoryTracker* tracker) const {
|
||||||
tracker->TrackFieldWithSize("protocol", url_pattern_.get_protocol().size());
|
tracker->TraitTrackInline(url_pattern_, "url_pattern");
|
||||||
tracker->TrackFieldWithSize("username", url_pattern_.get_username().size());
|
|
||||||
tracker->TrackFieldWithSize("password", url_pattern_.get_password().size());
|
|
||||||
tracker->TrackFieldWithSize("hostname", url_pattern_.get_hostname().size());
|
|
||||||
tracker->TrackFieldWithSize("pathname", url_pattern_.get_pathname().size());
|
|
||||||
tracker->TrackFieldWithSize("search", url_pattern_.get_search().size());
|
|
||||||
tracker->TrackFieldWithSize("hash", url_pattern_.get_hash().size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
|
void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
25
test/pummel/test-heapdump-urlpattern.js
Normal file
25
test/pummel/test-heapdump-urlpattern.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Flags: --expose-internals
|
||||||
|
'use strict';
|
||||||
|
require('../common');
|
||||||
|
const { validateSnapshotNodes } = require('../common/heap');
|
||||||
|
const { URLPattern } = require('node:url');
|
||||||
|
|
||||||
|
validateSnapshotNodes('Node / URLPattern', []);
|
||||||
|
const urlPattern = new URLPattern('https://example.com/:id');
|
||||||
|
validateSnapshotNodes('Node / URLPattern', [
|
||||||
|
{
|
||||||
|
children: [
|
||||||
|
{ node_name: 'Node / ada::url_pattern', edge_name: 'url_pattern' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
validateSnapshotNodes('Node / ada::url_pattern', [
|
||||||
|
{
|
||||||
|
children: [
|
||||||
|
{ node_name: 'Node / ada::url_pattern_component', edge_name: 'protocol_component' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Use `urlPattern`.
|
||||||
|
console.log(urlPattern);
|
Loading…
x
Reference in New Issue
Block a user