• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef COMMON_COMPONENTS_HEAP_COLLECTOR_GC_DEBUGGER_H
16 #define COMMON_COMPONENTS_HEAP_COLLECTOR_GC_DEBUGGER_H
17 
18 #include <algorithm>
19 #include <list>
20 #include <map>
21 #include <vector>
22 
23 #include "common_components/base/time_utils.h"
24 #include "common_components/log/log.h"
25 
26 #ifndef NDEBUG
27 #define GCINFO_DEBUG (false)
28 #else
29 #define GCINFO_DEBUG (false)
30 #endif
31 
32 namespace common {
33 #if defined(GCINFO_DEBUG) && GCINFO_DEBUG
34 class GCInfoNode {
35 public:
36     enum RootType {
37         REG_ROOT,
38         SLOT_ROOT,
39     };
BuildNodeForMarking(uintptr_t startIP,uintptr_t ip,FrameAddress * fa)40     static GCInfoNode BuildNodeForMarking(uintptr_t startIP, uintptr_t ip, FrameAddress* fa)
41     {
42         CString time = TimeUtil::GetTimestamp();
43 
44 #ifdef __APPLE__
45         FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(fa);
46 #else
47         FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(startIP);
48 #endif
49         return GCInfoNode(funcDesc->GetFuncName(), time, startIP, ip, reinterpret_cast<uintptr_t>(fa->returnAddress));
50     }
51     GCInfoNode() = default;
GCInfoNode(const CString & name,const CString & time,uintptr_t startIp,uintptr_t ip,uintptr_t retPC)52     GCInfoNode(const CString& name, const CString& time, uintptr_t startIp, uintptr_t ip, uintptr_t retPC)
53         : methodName(name), startPC(startIp), pc(ip), ra(retPC), timeStamp(time) {}
54     virtual ~GCInfoNode() = default;
DumpFrameGCInfo()55     virtual void DumpFrameGCInfo() const
56     {
57         DLOG(ENUM, "  time stamp: %s method name: %s, start ip: %p, frame pc: %p, return address: %p", timeStamp.Str(),
58              methodName.Str(), startPC, pc, ra);
59         DumpMapGCInfo(regRoots, "Register roots", "register: %d, root: %p  ");
60         DumpMapGCInfo(slotRoots, "Slot roots", "offset: %d, root: %p  ");
61         DumpMapGCInfo(invalidRegRoots, "Invalid register roots", "register id: %d, root: %p  ");
62         DumpMapGCInfo(invalidSlotRoots, "Invalid slot roots", "offset: %d, root: %p  ");
63     }
64     template<bool isValid = true>
InsertSlotRoots(SlotBias off,const BaseObject * ref)65     void InsertSlotRoots(SlotBias off, const BaseObject* ref)
66     {
67         if (isValid) {
68             slotRoots[off] = ref;
69         } else {
70             invalidSlotRoots[off] = ref;
71         }
72     }
73     template<bool isValid = true>
InsertRegRoot(RegisterNum reg,const BaseObject * ref)74     void InsertRegRoot(RegisterNum reg, const BaseObject* ref)
75     {
76         if (isValid) {
77             regRoots[reg] = ref;
78         } else {
79             invalidRegRoots[reg] = ref;
80         }
81     }
82 
83 protected:
84     template<class MapType>
DumpMapGCInfo(const MapType & rootMap,const CString & title,const CString & stringFormat)85     static void DumpMapGCInfo(const MapType& rootMap, const CString& title, const CString& stringFormat)
86     {
87         constexpr size_t numPerRow = 5;
88         constexpr size_t defaultCount = 0;
89         DLOG(ENUM, "    %s: {", title.Str());
90         size_t size = rootMap.size();
91         size_t remain = size % numPerRow;
92         size_t count = defaultCount;
93         CString detail = "";
94         for (auto x : rootMap) {
95             if (count == defaultCount) {
96                 detail.Append("     ");
97             }
98             detail.Append(CString::FormatString(stringFormat.Str(), x.first, x.second));
99             if (++count == numPerRow) {
100                 count = defaultCount;
101                 detail.Append("\n");
102             }
103         }
104         if (remain != defaultCount) {
105             detail.Append("\n");
106         }
107         detail.Append("    }\n");
108         DLOG(ENUM, "%s", detail.Str());
109     }
110 
111 private:
112     CString methodName;
113     uintptr_t startPC;
114     uintptr_t pc;
115     uintptr_t ra;
116     CString timeStamp;
117     std::map<RegisterNum, const BaseObject*> regRoots;
118     std::map<RegisterNum, const BaseObject*> invalidRegRoots;
119     std::map<SlotBias, const BaseObject*> slotRoots;
120     std::map<SlotBias, const BaseObject*> invalidSlotRoots;
121 };
122 
123 class GCInfoNodeForFix : public GCInfoNode {
124 public:
BuildNodeForFix(uintptr_t startIP,uintptr_t ip,FrameAddress * fa)125     static GCInfoNodeForFix BuildNodeForFix(uintptr_t startIP, uintptr_t ip, FrameAddress* fa)
126     {
127         CString time = TimeUtil::GetTimestamp();
128 
129 #ifdef __APPLE__
130         FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(fa);
131 #else
132         FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(startIP);
133 #endif
134         return GCInfoNodeForFix(funcDesc->GetFuncName(), time, startIP, ip,
135                                 reinterpret_cast<uintptr_t>(fa->returnAddress));
136     }
137     GCInfoNodeForFix() = default;
GCInfoNodeForFix(const CString & name,const CString & time,uintptr_t startIp,uintptr_t ip,uintptr_t retPC)138     GCInfoNodeForFix(const CString& name, const CString& time, uintptr_t startIp, uintptr_t ip, uintptr_t retPC)
139         : GCInfoNode(name, time, startIp, ip, retPC) {}
140     virtual ~GCInfoNodeForFix() = default;
InsertDerivedPtrRef(BasePtrType base,DerivedPtrType derived)141     void InsertDerivedPtrRef(BasePtrType base, DerivedPtrType derived) { derivedPtrRef[base] = derived; }
DumpFrameGCInfo()142     void DumpFrameGCInfo() const override
143     {
144         GCInfoNode::DumpFrameGCInfo();
145         DumpMapGCInfo(derivedPtrRef, "derived ptr references", "base object: %#zx, derived ptr: %#zx");
146     }
147 
148 private:
149     std::map<BasePtrType, DerivedPtrType> derivedPtrRef;
150 };
151 class CurrentGCInfo {
152 public:
~CurrentGCInfo()153     ~CurrentGCInfo(){};
PushFrameInfoForMarking(const GCInfoNode & frameGCInfo)154     void PushFrameInfoForMarking(const GCInfoNode& frameGCInfo) { gcInfosForMarking.push_back(frameGCInfo); }
PushFrameInfoForMarking(const GCInfoNode && frameGCInfo)155     void PushFrameInfoForMarking(const GCInfoNode&& frameGCInfo) { gcInfosForMarking.push_back(frameGCInfo); }
156 
PushFrameInfoForFix(const GCInfoNodeForFix & frameGCInfo)157     void PushFrameInfoForFix(const GCInfoNodeForFix& frameGCInfo) { gcInfosForFix.push_back(frameGCInfo); }
PushFrameInfoForFix(const GCInfoNodeForFix && frameGCInfo)158     void PushFrameInfoForFix(const GCInfoNodeForFix&& frameGCInfo) { gcInfosForFix.push_back(frameGCInfo); }
Clear()159     void Clear()
160     {
161         gcInfosForMarking.clear();
162         std::vector<GCInfoNode>().swap(gcInfosForMarking);
163         gcInfosForFix.clear();
164         std::vector<GCInfoNodeForFix>().swap(gcInfosForFix);
165     }
DumpFrameInfo()166     void DumpFrameInfo() const
167     {
168         DLOG(ENUM, "  fix roots info:");
169         std::for_each(gcInfosForFix.begin(), gcInfosForFix.end(),
170                       [](const GCInfoNodeForFix& info) { info.DumpFrameGCInfo(); });
171         DLOG(ENUM, "  marking roots info:");
172         std::for_each(gcInfosForMarking.begin(), gcInfosForMarking.end(),
173                       [](const GCInfoNode& info) { info.DumpFrameGCInfo(); });
174     }
175 
176 private:
177     std::vector<GCInfoNode> gcInfosForMarking;
178     std::vector<GCInfoNodeForFix> gcInfosForFix;
179 };
180 class GCInfos {
181 public:
182     GCInfos() = default;
183     ~GCInfos() = default;
CreateCurrentGCInfo()184     void CreateCurrentGCInfo()
185     {
186         constexpr size_t numLimit = 10;
187         if (gcInfos.size() >= numLimit) {
188             auto& front = gcInfos.front();
189             front.Clear();
190             gcInfos.pop_front();
191         }
192         gcInfos.push_back(CurrentGCInfo());
193     }
194 
PushFrameInfoForMarking(const GCInfoNode & frameGCInfo)195     void PushFrameInfoForMarking(const GCInfoNode& frameGCInfo)
196     {
197         GetCurrentGCInfo().PushFrameInfoForMarking(frameGCInfo);
198     }
199 
PushFrameInfoForMarking(const GCInfoNode && frameGCInfo)200     void PushFrameInfoForMarking(const GCInfoNode&& frameGCInfo)
201     {
202         GetCurrentGCInfo().PushFrameInfoForMarking(frameGCInfo);
203     }
204 
PushFrameInfoForFix(const GCInfoNodeForFix & infoNodeFoxFix)205     void PushFrameInfoForFix(const GCInfoNodeForFix& infoNodeFoxFix)
206     {
207         GetCurrentGCInfo().PushFrameInfoForFix(infoNodeFoxFix);
208     }
PushFrameInfoForFix(const GCInfoNodeForFix && infoNodeForFix)209     void PushFrameInfoForFix(const GCInfoNodeForFix&& infoNodeForFix)
210     {
211         GetCurrentGCInfo().PushFrameInfoForFix(infoNodeForFix);
212     }
213 
DumpGCInfos()214     void DumpGCInfos() const
215     {
216         size_t size = gcInfos.size();
217         DLOG(ENUM, " current thread happened %d times GC", size);
218         size_t i = 1;
219         std::for_each(gcInfos.rbegin(), gcInfos.rend(), [&i](const CurrentGCInfo& cur) {
220             DLOG(ENUM, " the %d scan stack: ", i++);
221             cur.DumpFrameInfo();
222         });
223     }
224 
225 private:
GetCurrentGCInfo()226     CurrentGCInfo& GetCurrentGCInfo()
227     {
228         if (UNLIKELY_CC(gcInfos.empty())) {
229             CreateCurrentGCInfo();
230         }
231         return gcInfos.back();
232     }
233     std::list<CurrentGCInfo> gcInfos;
234 };
235 #endif
236 } // namespace common
237 
238 #endif  // COMMON_COMPONENTS_HEAP_COLLECTOR_GC_DEBUGGER_H
239