14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_DFX_HPROF_HEAP_SNAPSHOT_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_DFX_HPROF_HEAP_SNAPSHOT_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <atomic>
204514f5e3Sopenharmony_ci#include <cstdint>
214514f5e3Sopenharmony_ci#include <fstream>
224514f5e3Sopenharmony_ci#include <sys/time.h>
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/heap_profiler.h"
254514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/heap_root_visitor.h"
264514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/string_hashmap.h"
274514f5e3Sopenharmony_ci#include "ecmascript/js_hclass.h"
284514f5e3Sopenharmony_ci#include "ecmascript/js_object.h"
294514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h"
304514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/method_literal.h"
314514f5e3Sopenharmony_ci#include "ecmascript/mem/c_containers.h"
324514f5e3Sopenharmony_ci#include "ecmascript/dfx/hprof/file_stream.h"
334514f5e3Sopenharmony_ci#include "ecmascript/interpreter/frame_handler.h"
344514f5e3Sopenharmony_ci#include "ecmascript/mem/object_xray.h"
354514f5e3Sopenharmony_ci#include "ecmascript/object_fast_operator.h"
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_cinamespace panda::ecmascript {
384514f5e3Sopenharmony_ciclass EntryIdMap;
394514f5e3Sopenharmony_ci// Define the Object Graphic
404514f5e3Sopenharmony_ciusing Address = uintptr_t;
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_cienum class NodeType {
434514f5e3Sopenharmony_ci    HIDDEN,
444514f5e3Sopenharmony_ci    ARRAY,
454514f5e3Sopenharmony_ci    STRING,
464514f5e3Sopenharmony_ci    OBJECT,
474514f5e3Sopenharmony_ci    CODE,
484514f5e3Sopenharmony_ci    CLOSURE,
494514f5e3Sopenharmony_ci    REGEXP,
504514f5e3Sopenharmony_ci    HEAPNUMBER,
514514f5e3Sopenharmony_ci    NATIVE,
524514f5e3Sopenharmony_ci    SYNTHETIC,
534514f5e3Sopenharmony_ci    CONSSTRING,
544514f5e3Sopenharmony_ci    SLICEDSTRING,
554514f5e3Sopenharmony_ci    SYMBOL,
564514f5e3Sopenharmony_ci    BIGINT,
574514f5e3Sopenharmony_ci    DEFAULT = NATIVE,
584514f5e3Sopenharmony_ci};
594514f5e3Sopenharmony_ci
604514f5e3Sopenharmony_cienum class EdgeType { CONTEXT, ELEMENT, PROPERTY, INTERNAL, HIDDEN, SHORTCUT, WEAK, DEFAULT = PROPERTY };
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_ciclass Node {
634514f5e3Sopenharmony_cipublic:
644514f5e3Sopenharmony_ci    Node(NodeId id, uint32_t index, const CString *name, NodeType type, size_t size, size_t nativeSize,
654514f5e3Sopenharmony_ci         uint32_t traceId, JSTaggedType address, bool isLive = true)
664514f5e3Sopenharmony_ci        : id_(id),
674514f5e3Sopenharmony_ci          index_(index),
684514f5e3Sopenharmony_ci          name_(name),
694514f5e3Sopenharmony_ci          type_(type),
704514f5e3Sopenharmony_ci          size_(size),
714514f5e3Sopenharmony_ci          nativeSize_(nativeSize),
724514f5e3Sopenharmony_ci          traceId_(traceId),
734514f5e3Sopenharmony_ci          address_(address),
744514f5e3Sopenharmony_ci          isLive_(isLive)
754514f5e3Sopenharmony_ci    {
764514f5e3Sopenharmony_ci    }
774514f5e3Sopenharmony_ci    NodeId GetId() const
784514f5e3Sopenharmony_ci    {
794514f5e3Sopenharmony_ci        return id_;
804514f5e3Sopenharmony_ci    }
814514f5e3Sopenharmony_ci    void SetIndex(uint32_t index)
824514f5e3Sopenharmony_ci    {
834514f5e3Sopenharmony_ci        index_ = index;
844514f5e3Sopenharmony_ci    }
854514f5e3Sopenharmony_ci    uint32_t GetIndex() const
864514f5e3Sopenharmony_ci    {
874514f5e3Sopenharmony_ci        return index_;
884514f5e3Sopenharmony_ci    }
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ci    const CString *GetName() const
914514f5e3Sopenharmony_ci    {
924514f5e3Sopenharmony_ci        return name_;
934514f5e3Sopenharmony_ci    }
944514f5e3Sopenharmony_ci
954514f5e3Sopenharmony_ci    void SetName(CString *name)
964514f5e3Sopenharmony_ci    {
974514f5e3Sopenharmony_ci        name_ = name;
984514f5e3Sopenharmony_ci    }
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_ci    NodeType GetType() const
1014514f5e3Sopenharmony_ci    {
1024514f5e3Sopenharmony_ci        return type_;
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci    size_t GetSelfSize() const
1054514f5e3Sopenharmony_ci    {
1064514f5e3Sopenharmony_ci        return size_;
1074514f5e3Sopenharmony_ci    }
1084514f5e3Sopenharmony_ci    void SetSelfSize(size_t size)
1094514f5e3Sopenharmony_ci    {
1104514f5e3Sopenharmony_ci        size_ = size;
1114514f5e3Sopenharmony_ci    }
1124514f5e3Sopenharmony_ci    size_t GetNativeSize() const
1134514f5e3Sopenharmony_ci    {
1144514f5e3Sopenharmony_ci        return nativeSize_;
1154514f5e3Sopenharmony_ci    }
1164514f5e3Sopenharmony_ci    void SetNativeSize(size_t size)
1174514f5e3Sopenharmony_ci    {
1184514f5e3Sopenharmony_ci        nativeSize_ = size;
1194514f5e3Sopenharmony_ci    }
1204514f5e3Sopenharmony_ci    size_t GetEdgeCount() const
1214514f5e3Sopenharmony_ci    {
1224514f5e3Sopenharmony_ci        return edgeCount_;
1234514f5e3Sopenharmony_ci    }
1244514f5e3Sopenharmony_ci    void IncEdgeCount()
1254514f5e3Sopenharmony_ci    {
1264514f5e3Sopenharmony_ci        edgeCount_++;
1274514f5e3Sopenharmony_ci    }
1284514f5e3Sopenharmony_ci    uint32_t GetStackTraceId() const
1294514f5e3Sopenharmony_ci    {
1304514f5e3Sopenharmony_ci        return traceId_;
1314514f5e3Sopenharmony_ci    }
1324514f5e3Sopenharmony_ci    JSTaggedType GetAddress() const
1334514f5e3Sopenharmony_ci    {
1344514f5e3Sopenharmony_ci        return address_;
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci    void SetAddress(JSTaggedType address)
1374514f5e3Sopenharmony_ci    {
1384514f5e3Sopenharmony_ci        address_ = address;
1394514f5e3Sopenharmony_ci    }
1404514f5e3Sopenharmony_ci    bool IsLive() const
1414514f5e3Sopenharmony_ci    {
1424514f5e3Sopenharmony_ci        return isLive_;
1434514f5e3Sopenharmony_ci    }
1444514f5e3Sopenharmony_ci    void SetLive(bool isLive)
1454514f5e3Sopenharmony_ci    {
1464514f5e3Sopenharmony_ci        isLive_ = isLive;
1474514f5e3Sopenharmony_ci    }
1484514f5e3Sopenharmony_ci    void SetTraceId(uint32_t traceId)
1494514f5e3Sopenharmony_ci    {
1504514f5e3Sopenharmony_ci        traceId_ = traceId;
1514514f5e3Sopenharmony_ci    }
1524514f5e3Sopenharmony_ci    static Node *NewNode(Chunk *chunk, NodeId id, size_t index, const CString *name, NodeType type, size_t size,
1534514f5e3Sopenharmony_ci                         size_t nativeSize, JSTaggedType entry, bool isLive = true);
1544514f5e3Sopenharmony_ci    template<typename T>
1554514f5e3Sopenharmony_ci    static JSTaggedType NewAddress(T *addr)
1564514f5e3Sopenharmony_ci    {
1574514f5e3Sopenharmony_ci        return reinterpret_cast<JSTaggedType>(addr);
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci    static constexpr int NODE_FIELD_COUNT = 8;
1604514f5e3Sopenharmony_ci    ~Node() = default;
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ciprivate:
1634514f5e3Sopenharmony_ci    NodeId id_ {0};  // Range from 1
1644514f5e3Sopenharmony_ci    uint32_t index_ {0};
1654514f5e3Sopenharmony_ci    const CString *name_ {nullptr};
1664514f5e3Sopenharmony_ci    NodeType type_ {NodeType::DEFAULT};
1674514f5e3Sopenharmony_ci    size_t size_ {0};
1684514f5e3Sopenharmony_ci    size_t nativeSize_ {0};
1694514f5e3Sopenharmony_ci    size_t edgeCount_ {0};
1704514f5e3Sopenharmony_ci    uint32_t traceId_ {0};
1714514f5e3Sopenharmony_ci    JSTaggedType address_ {0};
1724514f5e3Sopenharmony_ci    bool isLive_ {true};
1734514f5e3Sopenharmony_ci};
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_ciclass Edge {
1764514f5e3Sopenharmony_cipublic:
1774514f5e3Sopenharmony_ci    Edge(EdgeType type, Node *from, Node *to, CString *name)
1784514f5e3Sopenharmony_ci        : edgeType_(type), from_(from), to_(to), name_(name) {}
1794514f5e3Sopenharmony_ci    Edge(EdgeType type, Node *from, Node *to, uint32_t index)
1804514f5e3Sopenharmony_ci        : edgeType_(type), from_(from), to_(to), index_(index) {}
1814514f5e3Sopenharmony_ci    EdgeType GetType() const
1824514f5e3Sopenharmony_ci    {
1834514f5e3Sopenharmony_ci        return edgeType_;
1844514f5e3Sopenharmony_ci    }
1854514f5e3Sopenharmony_ci    const Node *GetFrom() const
1864514f5e3Sopenharmony_ci    {
1874514f5e3Sopenharmony_ci        return from_;
1884514f5e3Sopenharmony_ci    }
1894514f5e3Sopenharmony_ci    const Node *GetTo() const
1904514f5e3Sopenharmony_ci    {
1914514f5e3Sopenharmony_ci        return to_;
1924514f5e3Sopenharmony_ci    }
1934514f5e3Sopenharmony_ci    const CString *GetName() const
1944514f5e3Sopenharmony_ci    {
1954514f5e3Sopenharmony_ci        ASSERT(GetType() != EdgeType::ELEMENT);
1964514f5e3Sopenharmony_ci        return name_;
1974514f5e3Sopenharmony_ci    }
1984514f5e3Sopenharmony_ci    uint32_t GetIndex() const
1994514f5e3Sopenharmony_ci    {
2004514f5e3Sopenharmony_ci        ASSERT(GetType() == EdgeType::ELEMENT);
2014514f5e3Sopenharmony_ci        return index_;
2024514f5e3Sopenharmony_ci    }
2034514f5e3Sopenharmony_ci    void SetName(CString *name)
2044514f5e3Sopenharmony_ci    {
2054514f5e3Sopenharmony_ci        ASSERT(GetType() != EdgeType::ELEMENT);
2064514f5e3Sopenharmony_ci        name_ = name;
2074514f5e3Sopenharmony_ci    }
2084514f5e3Sopenharmony_ci    void UpdateFrom(Node *node)
2094514f5e3Sopenharmony_ci    {
2104514f5e3Sopenharmony_ci        from_ = node;
2114514f5e3Sopenharmony_ci    }
2124514f5e3Sopenharmony_ci    void UpdateTo(Node *node)
2134514f5e3Sopenharmony_ci    {
2144514f5e3Sopenharmony_ci        to_ = node;
2154514f5e3Sopenharmony_ci    }
2164514f5e3Sopenharmony_ci    static Edge *NewEdge(Chunk *chunk, EdgeType type, Node *from, Node *to, CString *name);
2174514f5e3Sopenharmony_ci    static Edge *NewEdge(Chunk *chunk, EdgeType type, Node *from, Node *to, uint32_t index);
2184514f5e3Sopenharmony_ci    static constexpr int EDGE_FIELD_COUNT = 3;
2194514f5e3Sopenharmony_ci    ~Edge() = default;
2204514f5e3Sopenharmony_ci
2214514f5e3Sopenharmony_ciprivate:
2224514f5e3Sopenharmony_ci    EdgeType edgeType_ {EdgeType::DEFAULT};
2234514f5e3Sopenharmony_ci    Node *from_ {nullptr};
2244514f5e3Sopenharmony_ci    Node *to_ {nullptr};
2254514f5e3Sopenharmony_ci    union {
2264514f5e3Sopenharmony_ci        CString *name_;
2274514f5e3Sopenharmony_ci        uint32_t index_;
2284514f5e3Sopenharmony_ci    };
2294514f5e3Sopenharmony_ci};
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_ciclass TimeStamp {
2324514f5e3Sopenharmony_cipublic:
2334514f5e3Sopenharmony_ci    explicit TimeStamp(int sequenceId) : lastSequenceId_(sequenceId), timeStampUs_(TimeStamp::Now()) {}
2344514f5e3Sopenharmony_ci    ~TimeStamp() = default;
2354514f5e3Sopenharmony_ci
2364514f5e3Sopenharmony_ci    DEFAULT_MOVE_SEMANTIC(TimeStamp);
2374514f5e3Sopenharmony_ci    DEFAULT_COPY_SEMANTIC(TimeStamp);
2384514f5e3Sopenharmony_ci
2394514f5e3Sopenharmony_ci    int GetLastSequenceId() const
2404514f5e3Sopenharmony_ci    {
2414514f5e3Sopenharmony_ci        return lastSequenceId_;
2424514f5e3Sopenharmony_ci    }
2434514f5e3Sopenharmony_ci
2444514f5e3Sopenharmony_ci    int64_t GetTimeStamp() const
2454514f5e3Sopenharmony_ci    {
2464514f5e3Sopenharmony_ci        return timeStampUs_;
2474514f5e3Sopenharmony_ci    }
2484514f5e3Sopenharmony_ci
2494514f5e3Sopenharmony_ci    uint32_t GetSize() const
2504514f5e3Sopenharmony_ci    {
2514514f5e3Sopenharmony_ci        return size_;
2524514f5e3Sopenharmony_ci    }
2534514f5e3Sopenharmony_ci
2544514f5e3Sopenharmony_ci    void SetSize(uint32_t size)
2554514f5e3Sopenharmony_ci    {
2564514f5e3Sopenharmony_ci        size_ = size;
2574514f5e3Sopenharmony_ci    }
2584514f5e3Sopenharmony_ci
2594514f5e3Sopenharmony_ci    uint32_t GetCount() const
2604514f5e3Sopenharmony_ci    {
2614514f5e3Sopenharmony_ci        return count_;
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci
2644514f5e3Sopenharmony_ci    void SetCount(uint32_t count)
2654514f5e3Sopenharmony_ci    {
2664514f5e3Sopenharmony_ci        count_ = count;
2674514f5e3Sopenharmony_ci    }
2684514f5e3Sopenharmony_ci
2694514f5e3Sopenharmony_ciprivate:
2704514f5e3Sopenharmony_ci    static int64_t Now()
2714514f5e3Sopenharmony_ci    {
2724514f5e3Sopenharmony_ci        struct timeval tv = {0, 0};
2734514f5e3Sopenharmony_ci        gettimeofday(&tv, nullptr);
2744514f5e3Sopenharmony_ci        const int THOUSAND = 1000;
2754514f5e3Sopenharmony_ci        return tv.tv_usec + tv.tv_sec * THOUSAND * THOUSAND;
2764514f5e3Sopenharmony_ci    }
2774514f5e3Sopenharmony_ci
2784514f5e3Sopenharmony_ci    int lastSequenceId_ {0};
2794514f5e3Sopenharmony_ci    int64_t timeStampUs_ {0};
2804514f5e3Sopenharmony_ci    uint32_t size_ {0};
2814514f5e3Sopenharmony_ci    uint32_t count_ {0};
2824514f5e3Sopenharmony_ci};
2834514f5e3Sopenharmony_ci
2844514f5e3Sopenharmony_ciclass HeapEntryMap {
2854514f5e3Sopenharmony_cipublic:
2864514f5e3Sopenharmony_ci    HeapEntryMap() = default;
2874514f5e3Sopenharmony_ci    ~HeapEntryMap() = default;
2884514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(HeapEntryMap);
2894514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(HeapEntryMap);
2904514f5e3Sopenharmony_ci    Node *FindOrInsertNode(Node *node);
2914514f5e3Sopenharmony_ci    Node *FindAndEraseNode(JSTaggedType addr);
2924514f5e3Sopenharmony_ci    Node *FindEntry(JSTaggedType addr);
2934514f5e3Sopenharmony_ci    void InsertEntry(Node *node);
2944514f5e3Sopenharmony_ci
2954514f5e3Sopenharmony_ciprivate:
2964514f5e3Sopenharmony_ci    CUnorderedMap<JSTaggedType, Node *> nodesMap_ {};
2974514f5e3Sopenharmony_ci};
2984514f5e3Sopenharmony_ci
2994514f5e3Sopenharmony_cistruct FunctionInfo {
3004514f5e3Sopenharmony_ci    int functionId = 0;
3014514f5e3Sopenharmony_ci    std::string functionName = "";
3024514f5e3Sopenharmony_ci    std::string scriptName = "";
3034514f5e3Sopenharmony_ci    int scriptId = 0;
3044514f5e3Sopenharmony_ci    int columnNumber = 0;
3054514f5e3Sopenharmony_ci    int lineNumber = 0;
3064514f5e3Sopenharmony_ci};
3074514f5e3Sopenharmony_ci
3084514f5e3Sopenharmony_ciclass TraceTree;
3094514f5e3Sopenharmony_ciclass TraceNode {
3104514f5e3Sopenharmony_cipublic:
3114514f5e3Sopenharmony_ci    TraceNode(TraceTree* tree, uint32_t nodeIndex);
3124514f5e3Sopenharmony_ci    ~TraceNode();
3134514f5e3Sopenharmony_ci
3144514f5e3Sopenharmony_ci    TraceNode(const TraceNode&) = delete;
3154514f5e3Sopenharmony_ci    TraceNode& operator=(const TraceNode&) = delete;
3164514f5e3Sopenharmony_ci    TraceNode* FindChild(uint32_t nodeIndex);
3174514f5e3Sopenharmony_ci    TraceNode* FindOrAddChild(uint32_t nodeIndex);
3184514f5e3Sopenharmony_ci    uint32_t GetNodeIndex() const
3194514f5e3Sopenharmony_ci    {
3204514f5e3Sopenharmony_ci        return nodeIndex_;
3214514f5e3Sopenharmony_ci    }
3224514f5e3Sopenharmony_ci    uint32_t GetTotalSize() const
3234514f5e3Sopenharmony_ci    {
3244514f5e3Sopenharmony_ci        return totalSize_;
3254514f5e3Sopenharmony_ci    }
3264514f5e3Sopenharmony_ci    uint32_t GetTotalCount() const
3274514f5e3Sopenharmony_ci    {
3284514f5e3Sopenharmony_ci        return totalCount_;
3294514f5e3Sopenharmony_ci    }
3304514f5e3Sopenharmony_ci    uint32_t GetId() const
3314514f5e3Sopenharmony_ci    {
3324514f5e3Sopenharmony_ci        return id_;
3334514f5e3Sopenharmony_ci    }
3344514f5e3Sopenharmony_ci    const std::vector<TraceNode*>& GetChildren() const
3354514f5e3Sopenharmony_ci    {
3364514f5e3Sopenharmony_ci        return children_;
3374514f5e3Sopenharmony_ci    }
3384514f5e3Sopenharmony_ci    TraceNode &SetTotalSize(uint32_t totalSize)
3394514f5e3Sopenharmony_ci    {
3404514f5e3Sopenharmony_ci        totalSize_ = totalSize;
3414514f5e3Sopenharmony_ci        return *this;
3424514f5e3Sopenharmony_ci    }
3434514f5e3Sopenharmony_ci    TraceNode &SetTotalCount(uint32_t totalCount)
3444514f5e3Sopenharmony_ci    {
3454514f5e3Sopenharmony_ci        totalCount_ = totalCount;
3464514f5e3Sopenharmony_ci        return *this;
3474514f5e3Sopenharmony_ci    }
3484514f5e3Sopenharmony_ci
3494514f5e3Sopenharmony_ciprivate:
3504514f5e3Sopenharmony_ci    TraceTree* tree_ {nullptr};
3514514f5e3Sopenharmony_ci    uint32_t nodeIndex_ {0};
3524514f5e3Sopenharmony_ci    uint32_t totalSize_ {0};
3534514f5e3Sopenharmony_ci    uint32_t totalCount_ {0};
3544514f5e3Sopenharmony_ci    uint32_t id_ {0};
3554514f5e3Sopenharmony_ci    std::vector<TraceNode*> children_ {};
3564514f5e3Sopenharmony_ci};
3574514f5e3Sopenharmony_ci
3584514f5e3Sopenharmony_ciclass TraceTree {
3594514f5e3Sopenharmony_cipublic:
3604514f5e3Sopenharmony_ci    TraceTree() : nextNodeId_(1), root_(this, 0)
3614514f5e3Sopenharmony_ci    {
3624514f5e3Sopenharmony_ci    }
3634514f5e3Sopenharmony_ci    ~TraceTree() = default;
3644514f5e3Sopenharmony_ci    TraceTree(const TraceTree&) = delete;
3654514f5e3Sopenharmony_ci    TraceTree& operator=(const TraceTree&) = delete;
3664514f5e3Sopenharmony_ci    TraceNode* AddNodeToTree(CVector<uint32_t> traceNodeIndex);
3674514f5e3Sopenharmony_ci    TraceNode* GetRoot()
3684514f5e3Sopenharmony_ci    {
3694514f5e3Sopenharmony_ci        return &root_;
3704514f5e3Sopenharmony_ci    }
3714514f5e3Sopenharmony_ci    uint32_t GetNextNodeId()
3724514f5e3Sopenharmony_ci    {
3734514f5e3Sopenharmony_ci        return nextNodeId_++;
3744514f5e3Sopenharmony_ci    }
3754514f5e3Sopenharmony_ci
3764514f5e3Sopenharmony_ciprivate:
3774514f5e3Sopenharmony_ci    uint32_t nextNodeId_ {0};
3784514f5e3Sopenharmony_ci    TraceNode root_;
3794514f5e3Sopenharmony_ci};
3804514f5e3Sopenharmony_ci
3814514f5e3Sopenharmony_cistruct Reference {
3824514f5e3Sopenharmony_ci    enum class ReferenceType { CONTEXT, ELEMENT, PROPERTY, INTERNAL, HIDDEN, SHORTCUT, WEAK, DEFAULT = PROPERTY };
3834514f5e3Sopenharmony_ci
3844514f5e3Sopenharmony_ci    Reference(const CString &name, JSTaggedValue value) : name_(name), value_(value) {}
3854514f5e3Sopenharmony_ci    Reference(const CString &name, JSTaggedValue value, ReferenceType type) : name_(name), value_(value), type_(type) {}
3864514f5e3Sopenharmony_ci    Reference(uint32_t index, JSTaggedValue value, ReferenceType type) : index_(index), value_(value), type_(type) {}
3874514f5e3Sopenharmony_ci
3884514f5e3Sopenharmony_ci    CString name_;
3894514f5e3Sopenharmony_ci    uint32_t index_ {-1U};
3904514f5e3Sopenharmony_ci    JSTaggedValue value_;
3914514f5e3Sopenharmony_ci    ReferenceType type_ {ReferenceType::DEFAULT};
3924514f5e3Sopenharmony_ci};
3934514f5e3Sopenharmony_ci
3944514f5e3Sopenharmony_ciclass EntryVisitor {
3954514f5e3Sopenharmony_cipublic:
3964514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(EntryVisitor);
3974514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(EntryVisitor);
3984514f5e3Sopenharmony_ci    EntryVisitor() = default;
3994514f5e3Sopenharmony_ci    ~EntryVisitor() = default;
4004514f5e3Sopenharmony_ci    static CString ConvertKey(JSTaggedValue key);
4014514f5e3Sopenharmony_ci};
4024514f5e3Sopenharmony_ci
4034514f5e3Sopenharmony_ciclass HeapSnapshot {
4044514f5e3Sopenharmony_cipublic:
4054514f5e3Sopenharmony_ci    static constexpr int SEQ_STEP = 2;
4064514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(HeapSnapshot);
4074514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(HeapSnapshot);
4084514f5e3Sopenharmony_ci    HeapSnapshot(const EcmaVM *vm, StringHashMap *stringTable, const DumpSnapShotOption &dumpOption,
4094514f5e3Sopenharmony_ci                 const bool trackAllocations, EntryIdMap *entryIdMap, Chunk *chunk)
4104514f5e3Sopenharmony_ci        : vm_(vm), stringTable_(stringTable), isVmMode_(dumpOption.isVmMode), isPrivate_(dumpOption.isPrivate),
4114514f5e3Sopenharmony_ci          captureNumericValue_(dumpOption.captureNumericValue), trackAllocations_(trackAllocations),
4124514f5e3Sopenharmony_ci          entryIdMap_(entryIdMap), chunk_(chunk) {}
4134514f5e3Sopenharmony_ci    ~HeapSnapshot();
4144514f5e3Sopenharmony_ci    bool BuildUp(bool isSimplify = false);
4154514f5e3Sopenharmony_ci    bool Verify();
4164514f5e3Sopenharmony_ci
4174514f5e3Sopenharmony_ci    void PrepareSnapshot();
4184514f5e3Sopenharmony_ci    void UpdateNodes(bool isInFinish = false);
4194514f5e3Sopenharmony_ci    Node *AddNode(TaggedObject *address, size_t size);
4204514f5e3Sopenharmony_ci    void MoveNode(uintptr_t address, TaggedObject *forwardAddress, size_t size);
4214514f5e3Sopenharmony_ci    void RecordSampleTime();
4224514f5e3Sopenharmony_ci    bool FinishSnapshot();
4234514f5e3Sopenharmony_ci    void PushHeapStat(Stream* stream);
4244514f5e3Sopenharmony_ci    int AddTraceNode(int sequenceId, int size);
4254514f5e3Sopenharmony_ci    bool AddMethodInfo(MethodLiteral *methodLiteral,
4264514f5e3Sopenharmony_ci                       const JSPandaFile *jsPandaFile, int sequenceId);
4274514f5e3Sopenharmony_ci    void AddTraceNodeId(MethodLiteral *methodLiteral);
4284514f5e3Sopenharmony_ci
4294514f5e3Sopenharmony_ci    const CVector<TimeStamp> &GetTimeStamps() const
4304514f5e3Sopenharmony_ci    {
4314514f5e3Sopenharmony_ci        return timeStamps_;
4324514f5e3Sopenharmony_ci    }
4334514f5e3Sopenharmony_ci
4344514f5e3Sopenharmony_ci    size_t GetNodeCount() const
4354514f5e3Sopenharmony_ci    {
4364514f5e3Sopenharmony_ci        return nodeCount_;
4374514f5e3Sopenharmony_ci    }
4384514f5e3Sopenharmony_ci    size_t GetEdgeCount() const
4394514f5e3Sopenharmony_ci    {
4404514f5e3Sopenharmony_ci        return edgeCount_;
4414514f5e3Sopenharmony_ci    }
4424514f5e3Sopenharmony_ci    size_t GetTotalNodeSize() const
4434514f5e3Sopenharmony_ci    {
4444514f5e3Sopenharmony_ci        return totalNodesSize_;
4454514f5e3Sopenharmony_ci    }
4464514f5e3Sopenharmony_ci    void AccumulateNodeSize(size_t size)
4474514f5e3Sopenharmony_ci    {
4484514f5e3Sopenharmony_ci        totalNodesSize_ += static_cast<int>(size);
4494514f5e3Sopenharmony_ci    }
4504514f5e3Sopenharmony_ci    void DecreaseNodeSize(size_t size)
4514514f5e3Sopenharmony_ci    {
4524514f5e3Sopenharmony_ci        totalNodesSize_ -= static_cast<int>(size);
4534514f5e3Sopenharmony_ci    }
4544514f5e3Sopenharmony_ci    CString *GenerateNodeName(TaggedObject *entry);
4554514f5e3Sopenharmony_ci    NodeType GenerateNodeType(TaggedObject *entry);
4564514f5e3Sopenharmony_ci    const CList<Node *> *GetNodes() const
4574514f5e3Sopenharmony_ci    {
4584514f5e3Sopenharmony_ci        return &nodes_;
4594514f5e3Sopenharmony_ci    }
4604514f5e3Sopenharmony_ci    const CList<Edge *> *GetEdges() const
4614514f5e3Sopenharmony_ci    {
4624514f5e3Sopenharmony_ci        return &edges_;
4634514f5e3Sopenharmony_ci    }
4644514f5e3Sopenharmony_ci
4654514f5e3Sopenharmony_ci    CString *GetString(const CString &as);
4664514f5e3Sopenharmony_ci    CString *GetArrayString(TaggedArray *array, const CString &as);
4674514f5e3Sopenharmony_ci
4684514f5e3Sopenharmony_ci    bool IsInVmMode() const
4694514f5e3Sopenharmony_ci    {
4704514f5e3Sopenharmony_ci        return isVmMode_;
4714514f5e3Sopenharmony_ci    }
4724514f5e3Sopenharmony_ci
4734514f5e3Sopenharmony_ci    bool IsPrivate() const
4744514f5e3Sopenharmony_ci    {
4754514f5e3Sopenharmony_ci        return isPrivate_;
4764514f5e3Sopenharmony_ci    }
4774514f5e3Sopenharmony_ci
4784514f5e3Sopenharmony_ci    bool trackAllocations() const
4794514f5e3Sopenharmony_ci    {
4804514f5e3Sopenharmony_ci        return trackAllocations_;
4814514f5e3Sopenharmony_ci    }
4824514f5e3Sopenharmony_ci
4834514f5e3Sopenharmony_ci    const CVector<FunctionInfo> &GetTrackAllocationsStack() const
4844514f5e3Sopenharmony_ci    {
4854514f5e3Sopenharmony_ci        return traceInfoStack_;
4864514f5e3Sopenharmony_ci    }
4874514f5e3Sopenharmony_ci
4884514f5e3Sopenharmony_ci    TraceTree* GetTraceTree()
4894514f5e3Sopenharmony_ci    {
4904514f5e3Sopenharmony_ci        return &traceTree_;
4914514f5e3Sopenharmony_ci    }
4924514f5e3Sopenharmony_ci
4934514f5e3Sopenharmony_ci    void PrepareTraceInfo()
4944514f5e3Sopenharmony_ci    {
4954514f5e3Sopenharmony_ci        struct FunctionInfo info;
4964514f5e3Sopenharmony_ci        info.functionName = "(root)";
4974514f5e3Sopenharmony_ci        GetString(info.functionName.c_str());
4984514f5e3Sopenharmony_ci        traceInfoStack_.push_back(info);
4994514f5e3Sopenharmony_ci    }
5004514f5e3Sopenharmony_ci    const StringHashMap *GetEcmaStringTable() const
5014514f5e3Sopenharmony_ci    {
5024514f5e3Sopenharmony_ci        return stringTable_;
5034514f5e3Sopenharmony_ci    }
5044514f5e3Sopenharmony_ci
5054514f5e3Sopenharmony_ci    bool BuildSnapshotForBinMod(CVector<RawHeapObjInfo *> &objInfoVec);
5064514f5e3Sopenharmony_ci    Node *GenerateNodeForBinMod(TaggedObject *obj, RawHeapObjInfo *objInfo,
5074514f5e3Sopenharmony_ci                                CUnorderedMap<uint64_t, const char *> &strTableIdMap);
5084514f5e3Sopenharmony_ci
5094514f5e3Sopenharmony_ci    StringId GenerateStringId(TaggedObject *obj)
5104514f5e3Sopenharmony_ci    {
5114514f5e3Sopenharmony_ci        JSTaggedValue entry(obj);
5124514f5e3Sopenharmony_ci        if (entry.IsOnlyJSObject()) {
5134514f5e3Sopenharmony_ci            return stringTable_->InsertStrAndGetStringId(ParseObjectName(obj));
5144514f5e3Sopenharmony_ci        }
5154514f5e3Sopenharmony_ci        if (entry.IsJSFunction()) {
5164514f5e3Sopenharmony_ci            return stringTable_->InsertStrAndGetStringId(ParseFunctionName(obj));
5174514f5e3Sopenharmony_ci        }
5184514f5e3Sopenharmony_ci        return 1; // 1 : invalid id
5194514f5e3Sopenharmony_ci    }
5204514f5e3Sopenharmony_ci
5214514f5e3Sopenharmony_ciprivate:
5224514f5e3Sopenharmony_ci    void FillNodes(bool isInFinish = false, bool isSimplify = false);
5234514f5e3Sopenharmony_ci    Node *GenerateNode(JSTaggedValue entry, size_t size = 0,
5244514f5e3Sopenharmony_ci                       bool isInFinish = false, bool isSimplify = false, bool isBinMod = false);
5254514f5e3Sopenharmony_ci    Node *HandleStringNode(JSTaggedValue &entry, size_t &size, bool &isInFinish, bool isBinMod);
5264514f5e3Sopenharmony_ci    Node *HandleFunctionNode(JSTaggedValue &entry, size_t &size, bool &isInFinish);
5274514f5e3Sopenharmony_ci    Node *HandleObjectNode(JSTaggedValue &entry, size_t &size, bool &isInFinish);
5284514f5e3Sopenharmony_ci    Node *HandleBaseClassNode(size_t size, bool idExist, NodeId &sequenceId,
5294514f5e3Sopenharmony_ci                              TaggedObject* obj, JSTaggedType &addr);
5304514f5e3Sopenharmony_ci    CString GeneratePrimitiveNameString(JSTaggedValue &entry);
5314514f5e3Sopenharmony_ci    Node *GeneratePrivateStringNode(size_t size);
5324514f5e3Sopenharmony_ci    Node *GenerateStringNode(JSTaggedValue entry, size_t size, bool isInFinish = false, bool isBinMod = false);
5334514f5e3Sopenharmony_ci    Node *GenerateFunctionNode(JSTaggedValue entry, size_t size, bool isInFinish = false);
5344514f5e3Sopenharmony_ci    Node *GenerateObjectNode(JSTaggedValue entry, size_t size, bool isInFinish = false);
5354514f5e3Sopenharmony_ci    void FillEdges(bool isSimplify = false);
5364514f5e3Sopenharmony_ci    void RenameFunction(const CString &edgeName, Node *entryFrom, Node *entryTo);
5374514f5e3Sopenharmony_ci    CString ParseFunctionName(TaggedObject *obj);
5384514f5e3Sopenharmony_ci    const CString ParseObjectName(TaggedObject *obj);
5394514f5e3Sopenharmony_ci
5404514f5e3Sopenharmony_ci    Node *InsertNodeUnique(Node *node);
5414514f5e3Sopenharmony_ci    void EraseNodeUnique(Node *node);
5424514f5e3Sopenharmony_ci    Edge *InsertEdgeUnique(Edge *edge);
5434514f5e3Sopenharmony_ci    void AddSyntheticRoot();
5444514f5e3Sopenharmony_ci    void FillEdgesForBinMod(RawHeapObjInfo *objInfo);
5454514f5e3Sopenharmony_ci    void AddSyntheticRootForBinMod(RawHeapObjInfo *objInfoVec, int &edgeOffset, Node *syntheticRoot);
5464514f5e3Sopenharmony_ci    Node *InsertNodeAt(size_t pos, Node *node);
5474514f5e3Sopenharmony_ci    Edge *InsertEdgeAt(size_t pos, Edge *edge);
5484514f5e3Sopenharmony_ci
5494514f5e3Sopenharmony_ci    CList<Node *> nodes_ {};
5504514f5e3Sopenharmony_ci    CList<Edge *> edges_ {};
5514514f5e3Sopenharmony_ci    CVector<TimeStamp> timeStamps_ {};
5524514f5e3Sopenharmony_ci    int nodeCount_ {0};
5534514f5e3Sopenharmony_ci    int edgeCount_ {0};
5544514f5e3Sopenharmony_ci    int totalNodesSize_ {0};
5554514f5e3Sopenharmony_ci    HeapEntryMap entryMap_;
5564514f5e3Sopenharmony_ci    panda::ecmascript::HeapRootVisitor rootVisitor_;
5574514f5e3Sopenharmony_ci    const EcmaVM *vm_;
5584514f5e3Sopenharmony_ci    StringHashMap *stringTable_ {nullptr};
5594514f5e3Sopenharmony_ci    bool isVmMode_ {true};
5604514f5e3Sopenharmony_ci    bool isPrivate_ {false};
5614514f5e3Sopenharmony_ci    bool captureNumericValue_ {false};
5624514f5e3Sopenharmony_ci    Node* privateStringNode_ {nullptr};
5634514f5e3Sopenharmony_ci    bool trackAllocations_ {false};
5644514f5e3Sopenharmony_ci    CVector<FunctionInfo> traceInfoStack_ {};
5654514f5e3Sopenharmony_ci    CMap<MethodLiteral *, struct FunctionInfo> stackInfo_;
5664514f5e3Sopenharmony_ci    CMap<std::string, int> scriptIdMap_;
5674514f5e3Sopenharmony_ci    TraceTree traceTree_;
5684514f5e3Sopenharmony_ci    CMap<MethodLiteral *, uint32_t> methodToTraceNodeId_;
5694514f5e3Sopenharmony_ci    CVector<uint32_t> traceNodeIndex_;
5704514f5e3Sopenharmony_ci    EntryIdMap* entryIdMap_;
5714514f5e3Sopenharmony_ci    Chunk *chunk_ {nullptr};
5724514f5e3Sopenharmony_ci};
5734514f5e3Sopenharmony_ci
5744514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
5754514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_DFX_HPROF_HEAP_SNAPSHOT_H
576