11cb0ef41Sopenharmony_ci#pragma once 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "v8-profiler.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <uv.h> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include <limits> 101cb0ef41Sopenharmony_ci#include <queue> 111cb0ef41Sopenharmony_ci#include <stack> 121cb0ef41Sopenharmony_ci#include <string> 131cb0ef41Sopenharmony_ci#include <unordered_map> 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_cinamespace v8 { 161cb0ef41Sopenharmony_ciclass BackingStore; 171cb0ef41Sopenharmony_ci} 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cinamespace node { 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_citemplate <typename T> 221cb0ef41Sopenharmony_cistruct MallocedBuffer; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci// Set the node name of a MemoryRetainer to klass 251cb0ef41Sopenharmony_ci#define SET_MEMORY_INFO_NAME(Klass) \ 261cb0ef41Sopenharmony_ci inline const char* MemoryInfoName() const override { return #Klass; } 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci// Set the self size of a MemoryRetainer to the stack-allocated size of a 291cb0ef41Sopenharmony_ci// certain class 301cb0ef41Sopenharmony_ci#define SET_SELF_SIZE(Klass) \ 311cb0ef41Sopenharmony_ci inline size_t SelfSize() const override { return sizeof(Klass); } 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci// Used when there is no additional fields to track 341cb0ef41Sopenharmony_ci#define SET_NO_MEMORY_INFO() \ 351cb0ef41Sopenharmony_ci inline void MemoryInfo(node::MemoryTracker* tracker) const override {} 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ciclass MemoryTracker; 381cb0ef41Sopenharmony_ciclass MemoryRetainerNode; 391cb0ef41Sopenharmony_citemplate <typename T, bool kIsWeak> 401cb0ef41Sopenharmony_ciclass BaseObjectPtrImpl; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_cinamespace crypto { 431cb0ef41Sopenharmony_ciclass NodeBIO; 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciclass CleanupHookCallback; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci/* Example: 491cb0ef41Sopenharmony_ci * 501cb0ef41Sopenharmony_ci * class ExampleRetainer : public MemoryRetainer { 511cb0ef41Sopenharmony_ci * public: 521cb0ef41Sopenharmony_ci * // Or use SET_NO_MEMORY_INFO() when there is no additional fields 531cb0ef41Sopenharmony_ci * // to track. 541cb0ef41Sopenharmony_ci * void MemoryInfo(MemoryTracker* tracker) const override { 551cb0ef41Sopenharmony_ci * // Node name and size comes from the MemoryInfoName and SelfSize of 561cb0ef41Sopenharmony_ci * // AnotherRetainerClass 571cb0ef41Sopenharmony_ci * tracker->TrackField("another_retainer", another_retainer_); 581cb0ef41Sopenharmony_ci * 591cb0ef41Sopenharmony_ci * // Add non_pointer_retainer as a separate node into the graph 601cb0ef41Sopenharmony_ci * // and track its memory information recursively. 611cb0ef41Sopenharmony_ci * // Note that we need to make sure its size is not accounted in 621cb0ef41Sopenharmony_ci * // ExampleRetainer::SelfSize(). 631cb0ef41Sopenharmony_ci * tracker->TrackField("non_pointer_retainer", &non_pointer_retainer_); 641cb0ef41Sopenharmony_ci * 651cb0ef41Sopenharmony_ci * // Specify node name and size explicitly 661cb0ef41Sopenharmony_ci * tracker->TrackFieldWithSize("internal_member", 671cb0ef41Sopenharmony_ci * internal_member_.size(), 681cb0ef41Sopenharmony_ci * "InternalClass"); 691cb0ef41Sopenharmony_ci * // Node name falls back to the edge name, 701cb0ef41Sopenharmony_ci * // elements in the container appear as grandchildren nodes 711cb0ef41Sopenharmony_ci * tracker->TrackField("vector", vector_); 721cb0ef41Sopenharmony_ci * // Node name and size come from the JS object 731cb0ef41Sopenharmony_ci * tracker->TrackField("target", target_); 741cb0ef41Sopenharmony_ci * } 751cb0ef41Sopenharmony_ci * 761cb0ef41Sopenharmony_ci * // Or use SET_MEMORY_INFO_NAME(ExampleRetainer) 771cb0ef41Sopenharmony_ci * const char* MemoryInfoName() const override { 781cb0ef41Sopenharmony_ci * return "ExampleRetainer"; 791cb0ef41Sopenharmony_ci * } 801cb0ef41Sopenharmony_ci * 811cb0ef41Sopenharmony_ci * // Classes that only want to return its sizeof() value can use the 821cb0ef41Sopenharmony_ci * // SET_SELF_SIZE(Class) macro instead. 831cb0ef41Sopenharmony_ci * size_t SelfSize() const override { 841cb0ef41Sopenharmony_ci * // We need to exclude the size of non_pointer_retainer so that 851cb0ef41Sopenharmony_ci * // we can track it separately in ExampleRetainer::MemoryInfo(). 861cb0ef41Sopenharmony_ci * return sizeof(ExampleRetainer) - sizeof(NonPointerRetainerClass); 871cb0ef41Sopenharmony_ci * } 881cb0ef41Sopenharmony_ci * 891cb0ef41Sopenharmony_ci * // Note: no need to implement these two methods when implementing 901cb0ef41Sopenharmony_ci * // a BaseObject or an AsyncWrap class 911cb0ef41Sopenharmony_ci * bool IsRootNode() const override { return !wrapped_.IsWeak(); } 921cb0ef41Sopenharmony_ci * v8::Local<v8::Object> WrappedObject() const override { 931cb0ef41Sopenharmony_ci * return node::PersistentToLocal::Default(wrapped_); 941cb0ef41Sopenharmony_ci * } 951cb0ef41Sopenharmony_ci * 961cb0ef41Sopenharmony_ci * private: 971cb0ef41Sopenharmony_ci * AnotherRetainerClass* another_retainer_; 981cb0ef41Sopenharmony_ci * NonPointerRetainerClass non_pointer_retainer; 991cb0ef41Sopenharmony_ci * InternalClass internal_member_; 1001cb0ef41Sopenharmony_ci * std::vector<uv_async_t> vector_; 1011cb0ef41Sopenharmony_ci * v8::Global<Object> target_; 1021cb0ef41Sopenharmony_ci * 1031cb0ef41Sopenharmony_ci * v8::Global<Object> wrapped_; 1041cb0ef41Sopenharmony_ci * } 1051cb0ef41Sopenharmony_ci * 1061cb0ef41Sopenharmony_ci * This creates the following graph: 1071cb0ef41Sopenharmony_ci * Node / ExampleRetainer 1081cb0ef41Sopenharmony_ci * |> another_retainer :: Node / AnotherRetainerClass 1091cb0ef41Sopenharmony_ci * |> internal_member :: Node / InternalClass 1101cb0ef41Sopenharmony_ci * |> vector :: Node / vector (elements will be grandchildren) 1111cb0ef41Sopenharmony_ci * |> [1] :: Node / uv_async_t (uv_async_t has predefined names) 1121cb0ef41Sopenharmony_ci * |> [2] :: Node / uv_async_t 1131cb0ef41Sopenharmony_ci * |> ... 1141cb0ef41Sopenharmony_ci * |> target :: TargetClass (JS class name of the target object) 1151cb0ef41Sopenharmony_ci * |> wrapped :: WrappedClass (JS class name of the wrapped object) 1161cb0ef41Sopenharmony_ci * |> wrapper :: Node / ExampleRetainer (back reference) 1171cb0ef41Sopenharmony_ci */ 1181cb0ef41Sopenharmony_ciclass MemoryRetainer { 1191cb0ef41Sopenharmony_ci public: 1201cb0ef41Sopenharmony_ci virtual ~MemoryRetainer() = default; 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // Subclasses should implement these methods to provide information 1231cb0ef41Sopenharmony_ci // for the V8 heap snapshot generator. 1241cb0ef41Sopenharmony_ci // The MemoryInfo() method is assumed to be called within a context 1251cb0ef41Sopenharmony_ci // where all the edges start from the node of the current retainer, 1261cb0ef41Sopenharmony_ci // and point to the nodes as specified by tracker->Track* calls. 1271cb0ef41Sopenharmony_ci virtual void MemoryInfo(MemoryTracker* tracker) const = 0; 1281cb0ef41Sopenharmony_ci virtual const char* MemoryInfoName() const = 0; 1291cb0ef41Sopenharmony_ci virtual size_t SelfSize() const = 0; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci virtual v8::Local<v8::Object> WrappedObject() const { 1321cb0ef41Sopenharmony_ci return v8::Local<v8::Object>(); 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci virtual bool IsRootNode() const { return false; } 1361cb0ef41Sopenharmony_ci virtual v8::EmbedderGraph::Node::Detachedness GetDetachedness() const { 1371cb0ef41Sopenharmony_ci return v8::EmbedderGraph::Node::Detachedness::kUnknown; 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci}; 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ciclass MemoryTracker { 1421cb0ef41Sopenharmony_ci public: 1431cb0ef41Sopenharmony_ci // Used to specify node name and size explicitly 1441cb0ef41Sopenharmony_ci inline void TrackFieldWithSize(const char* edge_name, 1451cb0ef41Sopenharmony_ci size_t size, 1461cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1471cb0ef41Sopenharmony_ci inline void TrackInlineFieldWithSize(const char* edge_name, 1481cb0ef41Sopenharmony_ci size_t size, 1491cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // Shortcut to extract the underlying object out of the smart pointer 1521cb0ef41Sopenharmony_ci template <typename T, typename D> 1531cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1541cb0ef41Sopenharmony_ci const std::unique_ptr<T, D>& value, 1551cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci template <typename T> 1581cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1591cb0ef41Sopenharmony_ci const std::shared_ptr<T>& value, 1601cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci template <typename T, bool kIsWeak> 1631cb0ef41Sopenharmony_ci void TrackField(const char* edge_name, 1641cb0ef41Sopenharmony_ci const BaseObjectPtrImpl<T, kIsWeak>& value, 1651cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci // For containers, the elements will be graphed as grandchildren nodes 1681cb0ef41Sopenharmony_ci // if the container is not empty. 1691cb0ef41Sopenharmony_ci // By default, we assume the parent count the stack size of the container 1701cb0ef41Sopenharmony_ci // into its SelfSize so that will be subtracted from the parent size when we 1711cb0ef41Sopenharmony_ci // spin off a new node for the container. 1721cb0ef41Sopenharmony_ci // TODO(joyeecheung): use RTTI to retrieve the class name at runtime? 1731cb0ef41Sopenharmony_ci template <typename T, typename Iterator = typename T::const_iterator> 1741cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1751cb0ef41Sopenharmony_ci const T& value, 1761cb0ef41Sopenharmony_ci const char* node_name = nullptr, 1771cb0ef41Sopenharmony_ci const char* element_name = nullptr, 1781cb0ef41Sopenharmony_ci bool subtract_from_self = true); 1791cb0ef41Sopenharmony_ci template <typename T> 1801cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1811cb0ef41Sopenharmony_ci const std::queue<T>& value, 1821cb0ef41Sopenharmony_ci const char* node_name = nullptr, 1831cb0ef41Sopenharmony_ci const char* element_name = nullptr); 1841cb0ef41Sopenharmony_ci template <typename T, typename U> 1851cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1861cb0ef41Sopenharmony_ci const std::pair<T, U>& value, 1871cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci // For the following types, node_name will be ignored and predefined names 1901cb0ef41Sopenharmony_ci // will be used instead. They are only in the signature for template 1911cb0ef41Sopenharmony_ci // expansion. 1921cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1931cb0ef41Sopenharmony_ci const MemoryRetainer& value, 1941cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1951cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 1961cb0ef41Sopenharmony_ci const MemoryRetainer* value, 1971cb0ef41Sopenharmony_ci const char* node_name = nullptr); 1981cb0ef41Sopenharmony_ci template <typename T> 1991cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2001cb0ef41Sopenharmony_ci const std::basic_string<T>& value, 2011cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2021cb0ef41Sopenharmony_ci template <typename T, 2031cb0ef41Sopenharmony_ci typename test_for_number = typename std:: 2041cb0ef41Sopenharmony_ci enable_if<std::numeric_limits<T>::is_specialized, bool>::type, 2051cb0ef41Sopenharmony_ci typename dummy = bool> 2061cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2071cb0ef41Sopenharmony_ci const T& value, 2081cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2091cb0ef41Sopenharmony_ci template <typename T> 2101cb0ef41Sopenharmony_ci void TrackField(const char* edge_name, 2111cb0ef41Sopenharmony_ci const v8::Eternal<T>& value, 2121cb0ef41Sopenharmony_ci const char* node_name); 2131cb0ef41Sopenharmony_ci template <typename T> 2141cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2151cb0ef41Sopenharmony_ci const v8::PersistentBase<T>& value, 2161cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2171cb0ef41Sopenharmony_ci template <typename T> 2181cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2191cb0ef41Sopenharmony_ci const v8::Local<T>& value, 2201cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2211cb0ef41Sopenharmony_ci template <typename T> 2221cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2231cb0ef41Sopenharmony_ci const MallocedBuffer<T>& value, 2241cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2251cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2261cb0ef41Sopenharmony_ci const v8::BackingStore* value, 2271cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2281cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2291cb0ef41Sopenharmony_ci const uv_buf_t& value, 2301cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2311cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2321cb0ef41Sopenharmony_ci const uv_timer_t& value, 2331cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2341cb0ef41Sopenharmony_ci inline void TrackField(const char* edge_name, 2351cb0ef41Sopenharmony_ci const uv_async_t& value, 2361cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2371cb0ef41Sopenharmony_ci inline void TrackInlineField(const char* edge_name, 2381cb0ef41Sopenharmony_ci const uv_async_t& value, 2391cb0ef41Sopenharmony_ci const char* node_name = nullptr); 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci // Put a memory container into the graph, create an edge from 2421cb0ef41Sopenharmony_ci // the current node if there is one on the stack. 2431cb0ef41Sopenharmony_ci inline void Track(const MemoryRetainer* retainer, 2441cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci // Useful for parents that do not wish to perform manual 2471cb0ef41Sopenharmony_ci // adjustments to its `SelfSize()` when embedding retainer 2481cb0ef41Sopenharmony_ci // objects inline. 2491cb0ef41Sopenharmony_ci // Put a memory container into the graph, create an edge from 2501cb0ef41Sopenharmony_ci // the current node if there is one on the stack - there should 2511cb0ef41Sopenharmony_ci // be one, of the container object which the current field is part of. 2521cb0ef41Sopenharmony_ci // Reduce the size of memory from the container so as to avoid 2531cb0ef41Sopenharmony_ci // duplication in accounting. 2541cb0ef41Sopenharmony_ci inline void TrackInlineField(const MemoryRetainer* retainer, 2551cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci inline v8::EmbedderGraph* graph() { return graph_; } 2581cb0ef41Sopenharmony_ci inline v8::Isolate* isolate() { return isolate_; } 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci inline explicit MemoryTracker(v8::Isolate* isolate, 2611cb0ef41Sopenharmony_ci v8::EmbedderGraph* graph) 2621cb0ef41Sopenharmony_ci : isolate_(isolate), graph_(graph) {} 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci private: 2651cb0ef41Sopenharmony_ci typedef std::unordered_map<const MemoryRetainer*, MemoryRetainerNode*> 2661cb0ef41Sopenharmony_ci NodeMap; 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci inline MemoryRetainerNode* CurrentNode() const; 2691cb0ef41Sopenharmony_ci inline MemoryRetainerNode* AddNode(const MemoryRetainer* retainer, 2701cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2711cb0ef41Sopenharmony_ci inline MemoryRetainerNode* PushNode(const MemoryRetainer* retainer, 2721cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2731cb0ef41Sopenharmony_ci inline MemoryRetainerNode* AddNode(const char* node_name, 2741cb0ef41Sopenharmony_ci size_t size, 2751cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2761cb0ef41Sopenharmony_ci inline MemoryRetainerNode* PushNode(const char* node_name, 2771cb0ef41Sopenharmony_ci size_t size, 2781cb0ef41Sopenharmony_ci const char* edge_name = nullptr); 2791cb0ef41Sopenharmony_ci inline void PopNode(); 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci v8::Isolate* isolate_; 2821cb0ef41Sopenharmony_ci v8::EmbedderGraph* graph_; 2831cb0ef41Sopenharmony_ci std::stack<MemoryRetainerNode*> node_stack_; 2841cb0ef41Sopenharmony_ci NodeMap seen_; 2851cb0ef41Sopenharmony_ci}; 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci} // namespace node 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 290