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