src: implement GetDetachedness() in MemoryRetainerNode
This allows us to mark weak/detached references in the heap snapshot. Also mark weak/detached BaseObject with Detachedness::kDetached so that the state of the reference can be displayed by frontend consuming the heap snapshot. PR-URL: https://github.com/nodejs/node/pull/44803 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
e84e2e6c85
commit
3ab2d4f362
@ -115,6 +115,11 @@ bool BaseObject::IsWeakOrDetached() const {
|
||||
return pd->wants_weak_jsobj || pd->is_detached;
|
||||
}
|
||||
|
||||
v8::EmbedderGraph::Node::Detachedness BaseObject::GetDetachedness() const {
|
||||
return IsWeakOrDetached() ? v8::EmbedderGraph::Node::Detachedness::kDetached
|
||||
: v8::EmbedderGraph::Node::Detachedness::kUnknown;
|
||||
}
|
||||
|
||||
template <int Field>
|
||||
void BaseObject::InternalFieldGet(
|
||||
v8::Local<v8::String> property,
|
||||
|
@ -96,6 +96,8 @@ class BaseObject : public MemoryRetainer {
|
||||
// to it anymore.
|
||||
inline bool IsWeakOrDetached() const;
|
||||
|
||||
inline v8::EmbedderGraph::Node::Detachedness GetDetachedness() const override;
|
||||
|
||||
// Utility to create a FunctionTemplate with one internal field (used for
|
||||
// the `BaseObject*` pointer) and a constructor that initializes that field
|
||||
// to `nullptr`.
|
||||
|
@ -31,6 +31,7 @@ class MemoryRetainerNode : public v8::EmbedderGraph::Node {
|
||||
|
||||
name_ = retainer_->MemoryInfoName();
|
||||
size_ = retainer_->SelfSize();
|
||||
detachedness_ = retainer_->GetDetachedness();
|
||||
}
|
||||
|
||||
inline MemoryRetainerNode(MemoryTracker* tracker,
|
||||
@ -57,6 +58,9 @@ class MemoryRetainerNode : public v8::EmbedderGraph::Node {
|
||||
}
|
||||
return is_root_node_;
|
||||
}
|
||||
v8::EmbedderGraph::Node::Detachedness GetDetachedness() override {
|
||||
return detachedness_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class MemoryTracker;
|
||||
@ -73,6 +77,8 @@ class MemoryRetainerNode : public v8::EmbedderGraph::Node {
|
||||
bool is_root_node_ = false;
|
||||
std::string name_;
|
||||
size_t size_ = 0;
|
||||
v8::EmbedderGraph::Node::Detachedness detachedness_ =
|
||||
v8::EmbedderGraph::Node::Detachedness::kUnknown;
|
||||
};
|
||||
|
||||
void MemoryTracker::TrackFieldWithSize(const char* edge_name,
|
||||
|
@ -127,6 +127,9 @@ class MemoryRetainer {
|
||||
}
|
||||
|
||||
virtual bool IsRootNode() const { return false; }
|
||||
virtual v8::EmbedderGraph::Node::Detachedness GetDetachedness() const {
|
||||
return v8::EmbedderGraph::Node::Detachedness::kUnknown;
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryTracker {
|
||||
|
@ -142,6 +142,22 @@ class State {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expectation.detachedness !== undefined) {
|
||||
const matchedNodes = rootNodes.filter(
|
||||
(node) => node.detachedness === expectation.detachedness);
|
||||
if (loose) {
|
||||
assert(matchedNodes.length >= rootNodes.length,
|
||||
`Expect to find at least ${rootNodes.length} with ` +
|
||||
`detachedness ${expectation.detachedness}, ` +
|
||||
`found ${matchedNodes.length}`);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
matchedNodes.length, rootNodes.length,
|
||||
`Expect to find ${rootNodes.length} with detachedness ` +
|
||||
`${expectation.detachedness}, found ${matchedNodes.length}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ validateSnapshotNodes('Node / ChannelWrap', [
|
||||
{ node_name: 'Node / NodeAresTask::List', edge_name: 'task_list' },
|
||||
// `Node / ChannelWrap` (C++) -> `ChannelWrap` (JS)
|
||||
{ node_name: 'ChannelWrap', edge_name: 'wrapped' },
|
||||
]
|
||||
],
|
||||
detachedness: 2
|
||||
},
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user