• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 
16 #ifndef ECMASCRIPT_PGO_PROFILER_INFO_H
17 #define ECMASCRIPT_PGO_PROFILER_INFO_H
18 
19 #include <cstdint>
20 #include <memory>
21 #include <sstream>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <utility>
25 #include <string.h>
26 
27 #include "ecmascript/common.h"
28 #include "ecmascript/jspandafile/method_literal.h"
29 #include "ecmascript/log_wrapper.h"
30 #include "ecmascript/mem/c_containers.h"
31 #include "ecmascript/mem/c_string.h"
32 #include "ecmascript/mem/chunk_containers.h"
33 #include "ecmascript/mem/native_area_allocator.h"
34 #include "ecmascript/mem/slots.h"
35 #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
36 #include "ecmascript/pgo_profiler/ap_file/pgo_method_type_set.h"
37 #include "ecmascript/pgo_profiler/ap_file/pgo_profile_type_pool.h"
38 #include "ecmascript/pgo_profiler/ap_file/pgo_proto_transition_type_pool.h"
39 #include "ecmascript/pgo_profiler/ap_file/pgo_record_pool.h"
40 #include "ecmascript/pgo_profiler/pgo_context.h"
41 #include "ecmascript/pgo_profiler/pgo_profiler.h"
42 #include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
43 #include "ecmascript/pgo_profiler/pgo_utils.h"
44 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
45 #include "ecmascript/property_attributes.h"
46 #include "ecmascript/ts_types/global_type_info.h"
47 #include "macros.h"
48 
49 namespace panda::ecmascript::pgo {
50 class SaveTask;
51 class PGOContext;
52 
53 class PGOPandaFileInfos {
54 public:
Sample(uint32_t checksum,uint32_t abcId)55     void Sample(uint32_t checksum, uint32_t abcId)
56     {
57         fileInfos_.emplace(checksum, abcId);
58     }
59 
Clear()60     void Clear()
61     {
62         fileInfos_.clear();
63     }
64 
GetFileInfosSzie()65     uint32_t GetFileInfosSzie() const
66     {
67         return fileInfos_.size();
68     }
69 
SampleSafe(uint32_t checksum,uint32_t abcId)70     void SampleSafe(uint32_t checksum, uint32_t abcId)
71     {
72         WriteLockHolder lock(fileInfosLock_);
73         Sample(checksum, abcId);
74     }
75 
ClearSafe()76     void ClearSafe()
77     {
78         WriteLockHolder lock(fileInfosLock_);
79         Clear();
80     }
81 
82     void ParseFromBinary(void *buffer, SectionInfo *const info);
83     void ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const;
84     void Merge(const PGOPandaFileInfos &pandaFileInfos);
85     void MergeSafe(const PGOPandaFileInfos& pandaFileInfos);
86     bool VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
87                         const std::string &incoming) const;
88 
89     void ProcessToText(std::ofstream &stream) const;
90 
91     bool Checksum(const std::unordered_map<CString, uint32_t>& fileNameToChecksumMap,
92                   const std::shared_ptr<PGOAbcFilePool>& abcFilePool_) const;
93     bool Checksum(const std::unordered_map<CString, uint32_t>& fileNameToChecksumMap) const;
94     void UpdateFileInfosAbcID(const PGOContext &context);
95 
96     template <typename Callback>
ForEachFileInfo(Callback callback)97     void ForEachFileInfo(Callback callback) const
98     {
99         for (const auto &fileInfo : fileInfos_) {
100             callback(fileInfo.GetChecksum(), fileInfo.GetAbcId());
101         }
102     }
103 
104 private:
105     class FileInfo {
106     public:
107         FileInfo() = default;
FileInfo(uint32_t checksum,uint32_t abcId)108         FileInfo(uint32_t checksum, uint32_t abcId) : abcId_(abcId), checksum_(checksum) {}
Size()109         static size_t Size()
110         {
111             return sizeof(FileInfo);
112         }
113 
114         bool operator<(const FileInfo &right) const
115         {
116             return abcId_ < right.abcId_;
117         }
118 
GetChecksum()119         uint32_t GetChecksum() const
120         {
121             return checksum_;
122         }
123 
GetAbcId()124         uint32_t GetAbcId() const
125         {
126             return abcId_;
127         }
128 
129     private:
130         // Support extended fields
131         uint32_t abcId_;
132         uint32_t checksum_;
133     };
134 
135     std::set<FileInfo> fileInfos_;
136     RWLock fileInfosLock_;
137 };
138 
139 class PGOMethodInfo {
140 public:
141     static constexpr int METHOD_INFO_COUNT = 4;
142     static constexpr int METHOD_ID_INDEX = 0;
143     static constexpr int METHOD_COUNT_INDEX = 1;
144     static constexpr int METHOD_MODE_INDEX = 2;
145     static constexpr int METHOD_NAME_INDEX = 3;
146     static constexpr uint32_t METHOD_MAX_HIT_COUNT = 10000U;
147 
PGOMethodInfo(PGOMethodId id)148     explicit PGOMethodInfo(PGOMethodId id) : id_(id) {}
149 
PGOMethodInfo(PGOMethodId id,uint32_t count,SampleMode mode,const char * methodName)150     PGOMethodInfo(PGOMethodId id, uint32_t count, SampleMode mode, const char *methodName)
151         : id_(id), count_(count), mode_(mode)
152     {
153         size_t len = strlen(methodName);
154         size_ = static_cast<uint32_t>(Size(len));
155         if (len > 0 && memcpy_s(&methodName_, len, methodName, len) != EOK) {
156             LOG_ECMA(ERROR) << "SetMethodName memcpy_s failed" << methodName << ", len = " << len;
157             UNREACHABLE();
158         }
159         *(&methodName_ + len) = '\0';
160     }
161 
162     static uint32_t PUBLIC_API CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength);
163 
164     static uint32_t CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength);
165 
Size(uint32_t length)166     static int32_t Size(uint32_t length)
167     {
168         return sizeof(PGOMethodInfo) + AlignUp(length, GetAlignmentInBytes(ALIGN_SIZE));
169     }
170 
Size()171     int32_t Size() const
172     {
173         return size_;
174     }
175 
GetSampleMode(std::string content,SampleMode & mode)176     static bool GetSampleMode(std::string content, SampleMode &mode)
177     {
178         if (content == "HOTNESS_MODE") {
179             mode = SampleMode::HOTNESS_MODE;
180         } else if (content == "CALL_MODE") {
181             mode = SampleMode::CALL_MODE;
182         } else {
183             return false;
184         }
185         return true;
186     }
187 
IncreaseCount()188     void IncreaseCount()
189     {
190         count_++;
191     }
192 
ClearCount()193     void ClearCount()
194     {
195         count_ = 0;
196     }
197 
Merge(const PGOMethodInfo * info)198     void Merge(const PGOMethodInfo *info)
199     {
200         if (!(id_ == info->GetMethodId())) {
201             LOG_ECMA(ERROR) << "The method id must same for merging";
202             return;
203         }
204         count_ = std::min(count_ + info->GetCount(), METHOD_MAX_HIT_COUNT);
205         SetSampleMode(info->GetSampleMode());
206     }
207 
GetMethodId()208     PGOMethodId GetMethodId() const
209     {
210         return id_;
211     }
212 
GetCount()213     uint32_t GetCount() const
214     {
215         return count_;
216     }
217 
GetMethodName()218     const char *GetMethodName() const
219     {
220         return &methodName_;
221     }
222 
SetSampleMode(SampleMode mode)223     void SetSampleMode(SampleMode mode)
224     {
225         if (mode_ == SampleMode::HOTNESS_MODE) {
226             return;
227         }
228         mode_ = mode;
229     }
230 
GetSampleMode()231     SampleMode GetSampleMode() const
232     {
233         return mode_;
234     }
235 
GetSampleModeToString()236     std::string GetSampleModeToString() const
237     {
238         std::string result;
239         switch (mode_) {
240             case SampleMode::HOTNESS_MODE:
241                 result = "HOTNESS_MODE";
242                 break;
243             case SampleMode::CALL_MODE:
244                 result = "CALL_MODE";
245                 break;
246             default:
247                 LOG_ECMA(ERROR) << "mode error";
248         }
249         return result;
250     }
251 
IsFilter(uint32_t threshold)252     bool IsFilter(uint32_t threshold) const
253     {
254         if (count_ < threshold && mode_ == SampleMode::CALL_MODE) {
255             return true;
256         }
257         return false;
258     }
259 
260     void ParseFromBinary(void **buffer);
261     void ProcessToBinary(std::ofstream &fileStream) const;
262 
263     static std::vector<std::string> ParseFromText(const std::string &infoString);
264     void ProcessToText(std::string &text) const;
265 
266     void ProcessToJson(ProfileType::VariantMap &function) const;
267 
268     NO_COPY_SEMANTIC(PGOMethodInfo);
269     NO_MOVE_SEMANTIC(PGOMethodInfo);
270 
271 private:
272     uint32_t size_ {0};
273     PGOMethodId id_;
274     uint32_t count_ {0};
275     SampleMode mode_ {SampleMode::CALL_MODE};
276     char methodName_ {0};
277 };
278 
279 class PGODecodeMethodInfo {
280 public:
PGODecodeMethodInfo(PGOMethodId id)281     explicit PGODecodeMethodInfo(PGOMethodId id) : methodId_(id) {}
282 
GetMethodId()283     PGOMethodId GetMethodId() const
284     {
285         return methodId_;
286     }
287 
GetPGOMethodTypeSet()288     PGOMethodTypeSet &GetPGOMethodTypeSet()
289     {
290         return pgoMethodTypeSet_;
291     }
292 
293     void Merge(const PGODecodeMethodInfo &from);
294 
295 private:
296     PGOMethodId methodId_ {0};
297     PGOMethodTypeSet pgoMethodTypeSet_ {};
298 };
299 
300 class PGOMethodInfoMap {
301 public:
302     PGOMethodInfoMap() = default;
303 
Clear()304     void Clear()
305     {
306         // PGOMethodInfo release by chunk
307         for (auto &entry : methodTypeInfos_) {
308             entry.second->Clear();
309         }
310         methodInfos_.clear();
311         methodTypeInfos_.clear();
312     }
313 
314     bool AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode);
315     bool AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type);
316     bool AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type);
317     bool AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
318     bool AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGODefineOpType type);
319     void Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos);
320 
321     bool ParseFromBinary(Chunk *chunk, PGOContext &context, void **buffer);
322     bool ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task,
323                          std::fstream &fileStream, PGOProfilerHeader *const header) const;
324 
325     bool ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content);
326     void ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const;
327 
328     void ProcessToJson(uint32_t threshold, ProfileType::jModuleType &jModule) const;
329 
GetMethodInfos()330     const CMap<PGOMethodId, PGOMethodInfo *> &GetMethodInfos() const
331     {
332         return methodInfos_;
333     }
334 
335     NO_COPY_SEMANTIC(PGOMethodInfoMap);
336     NO_MOVE_SEMANTIC(PGOMethodInfoMap);
337 
338 private:
339     PGOMethodTypeSet *GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId);
340 
341     CMap<PGOMethodId, PGOMethodInfo *> methodInfos_;
342     CMap<PGOMethodId, PGOMethodTypeSet *> methodTypeInfos_;
343     CMap<PGOMethodId, uint32_t> methodsChecksum_;
344     CMap<PGOSampleType, CMap<CString, TrackType>> globalLayoutDescInfos_;
345 };
346 
347 class PGOMethodIdSet {
348 public:
PGOMethodIdSet(Chunk * chunk)349     explicit PGOMethodIdSet(Chunk* chunk): chunk_(chunk), methodInfoMap_(chunk) {};
350     ~PGOMethodIdSet() = default;
351 
Clear()352     void Clear()
353     {
354         candidateSet_.clear();
355         for (auto &methodNameSet : methodInfoMap_) {
356             methodNameSet.second.Clear();
357         }
358         methodInfoMap_.clear();
359     }
360 
Match(EntityId methodId)361     bool Match(EntityId methodId)
362     {
363         return candidateSet_.find(methodId) != candidateSet_.end();
364     }
365 
366     template <typename Callback>
Update(const CString & recordName,Callback callback)367     bool Update(const CString &recordName, Callback callback)
368     {
369         std::unordered_set<EntityId> newIds = callback(recordName, candidateSet_);
370         if (!newIds.empty()) {
371             candidateSet_.insert(newIds.begin(), newIds.end());
372             return true;
373         }
374         return false;
375     }
376 
377     template <typename Callback>
GetTypeInfo(const char * methodName,Callback callback)378     void GetTypeInfo(const char *methodName, Callback callback)
379     {
380         // for no function checksum in ap file
381         auto iter = methodInfoMap_.find(methodName);
382         if ((iter != methodInfoMap_.end()) && (iter->second.GetFirstMethodInfo() != nullptr)) {
383             iter->second.GetFirstMethodInfo()->GetPGOMethodTypeSet().GetTypeInfo(callback);
384         }
385     }
386 
387     template <typename Callback>
GetTypeInfo(const char * methodName,uint32_t checksum,Callback callback)388     void GetTypeInfo(const char *methodName, uint32_t checksum, Callback callback)
389     {
390         auto iter = methodInfoMap_.find(methodName);
391         if ((iter != methodInfoMap_.end()) && (iter->second.GetMethodInfo(checksum) != nullptr)) {
392             return iter->second.GetMethodInfo(checksum)->GetPGOMethodTypeSet().GetTypeInfo(callback);
393         }
394         LOG_ECMA(DEBUG) << "Method checksum mismatched, name: " << methodName;
395     }
396 
MatchAndMarkMethod(const char * methodName,EntityId methodId)397     void MatchAndMarkMethod(const char *methodName, EntityId methodId)
398     {
399         const auto &iter = methodInfoMap_.find(methodName);
400         if (iter == methodInfoMap_.end()) {
401             // no matching method in PGO file.
402             return;
403         }
404         candidateSet_.emplace(methodId);
405         iter->second.SetMatch();
406     }
407 
408     bool ParseFromBinary(PGOContext &context, void **buffer);
409 
410     void GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount,
411                            std::set<std::pair<std::string, CString>> &mismatchMethodSet) const;
412 
413     void Merge(const PGOMethodIdSet &from);
414 
415     class PGOMethodNameSet {
416     public:
PGOMethodNameSet(Chunk * chunk)417         explicit PGOMethodNameSet(Chunk* chunk): methodMap_(chunk) {};
SetMatch()418         void SetMatch()
419         {
420             methodNameMatch_ = true;
421         }
422 
IsMatch()423         bool IsMatch() const
424         {
425             return methodNameMatch_;
426         }
427 
GetOrCreateMethodInfo(uint32_t checksum,PGOMethodId methodId)428         PGODecodeMethodInfo& GetOrCreateMethodInfo(uint32_t checksum, PGOMethodId methodId)
429         {
430             auto methodIter = methodMap_.find(checksum);
431             if (methodIter == methodMap_.end()) {
432                 auto ret = methodMap_.emplace(checksum, methodId);
433                 ASSERT(ret.second);
434                 methodIter = ret.first;
435             }
436             return methodIter->second;
437         }
438 
Merge(const PGOMethodNameSet & from)439         void Merge(const PGOMethodNameSet &from)
440         {
441             for (const auto &method : from.methodMap_) {
442                 uint32_t checksum = method.first;
443                 auto methodInfo = methodMap_.find(checksum);
444                 if (methodInfo == methodMap_.end()) {
445                     auto ret = methodMap_.emplace(checksum, method.second.GetMethodId());
446                     ASSERT(ret.second);
447                     methodInfo = ret.first;
448                 }
449                 methodInfo->second.Merge(method.second);
450             }
451         }
452 
GetFirstMethodInfo()453         PGODecodeMethodInfo *GetFirstMethodInfo()
454         {
455             if (methodMap_.empty()) {
456                 return nullptr;
457             }
458             return &(methodMap_.begin()->second);
459         }
460 
GetMethodInfo(uint32_t checksum)461         PGODecodeMethodInfo *GetMethodInfo(uint32_t checksum)
462         {
463             auto methodInfo = methodMap_.find(checksum);
464             if (methodInfo == methodMap_.end()) {
465                 return nullptr;
466             }
467             return &(methodInfo->second);
468         }
469 
Clear()470         void Clear()
471         {
472             methodMap_.clear();
473         }
474 
475     private:
476         bool methodNameMatch_ {false};
477         ChunkUnorderedMap<uint32_t, PGODecodeMethodInfo> methodMap_;
478     };
479 
480     NO_COPY_SEMANTIC(PGOMethodIdSet);
481     NO_MOVE_SEMANTIC(PGOMethodIdSet);
482 
483 private:
484     Chunk* chunk_;
485     std::unordered_set<EntityId> candidateSet_; // methodId in abc file, DO NOT for pgo internal use
486     ChunkUnorderedMap<CString, PGOMethodNameSet> methodInfoMap_;
487 };
488 
489 class PGORecordDetailInfos : public PGOContext {
490 public:
491     explicit PGORecordDetailInfos(uint32_t hotnessThreshold);
492 
493     ~PGORecordDetailInfos() override;
494 
495     void Clear();
496     void ClearSafe();
497     void InitSections();
498 
499     // If it is a new method, return true.
500     bool AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode);
501     bool AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type);
502     bool AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type);
503     bool AddObjectInfo(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
504     bool AddDefine(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGODefineOpType type);
505 
506     bool AddRwUseInfo(ProfileType rootType);
507     bool AddRootLayout(JSTaggedType hclass, ProfileType rootType);
508     bool UpdateTransitionLayout(
509         ProfileType rootType, JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType);
510     bool UpdateLayout(ProfileType rootType, JSTaggedType hclass, ProfileType curType);
511     void AddRootPtType(ProfileType rootType, ProfileType ptType);
512     bool IsDumped(ProfileType rootType, ProfileType curType) const;
513 
514     void Merge(const PGORecordDetailInfos &recordInfos);
515     void MergeSafe(const PGORecordDetailInfos& recordInfos);
516 
517     void UpdateLayout();
518 
519     bool ParseFromBinary(void *buffer, PGOProfilerHeader *const header);
520     void ProcessToBinary(const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header);
521 
522     void ProcessToText(std::ofstream &stream) const;
523 
GetRecordInfos()524     const CMap<ProfileType, PGOMethodInfoMap *> &GetRecordInfos() const
525     {
526         return recordInfos_;
527     }
528 
GetRecordPool()529     std::shared_ptr<PGORecordPool> GetRecordPool() const
530     {
531         return recordPool_;
532     }
533 
GetProfileTypePool()534     std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
535     {
536         return profileTypePool_;
537     }
538 
GetProtoTransitionPool()539     std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const
540     {
541         return protoTransitionPool_;
542     }
543 
GetHotnessThreshold()544     uint32_t GetHotnessThreshold() const override
545     {
546         return hotnessThreshold_;
547     }
548 
GetHeader()549     PGOProfilerHeader *GetHeader() const override
550     {
551         return header_;
552     }
553 
SupportElementsKind()554     bool SupportElementsKind() const override
555     {
556         ASSERT(header_ != nullptr);
557         return header_->SupportElementsKind();
558     }
559 
SupportElementsTrackInfo()560     bool SupportElementsTrackInfo() const override
561     {
562         ASSERT(header_ != nullptr);
563         return header_->SupportElementsTrackInfo();
564     }
565 
ResetAbcIdRemap()566     void ResetAbcIdRemap() const override
567     {
568         abcIdRemap_.clear();
569     }
570 
AddAbcIdRemap(ApEntityId oldId,ApEntityId newId)571     void AddAbcIdRemap(ApEntityId oldId, ApEntityId newId) const override
572     {
573         abcIdRemap_[oldId] = newId;
574     }
575 
GetAbcIdRemap()576     const std::map<ApEntityId, ApEntityId> &GetAbcIdRemap() const override
577     {
578         return abcIdRemap_;
579     }
580 
581     NO_COPY_SEMANTIC(PGORecordDetailInfos);
582     NO_MOVE_SEMANTIC(PGORecordDetailInfos);
583 
584 private:
585     PGOMethodInfoMap *GetMethodInfoMap(ProfileType recordProfileType);
586     bool ParseFromBinaryForLayout(void **buffer);
587     bool ProcessToBinaryForLayout(NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream);
588 
589     uint32_t hotnessThreshold_ {2};
590     NativeAreaAllocator nativeAreaAllocator_;
591     std::unique_ptr<Chunk> chunk_;
592     CMap<ProfileType, PGOMethodInfoMap *> recordInfos_;
593     std::set<PGOHClassTreeDesc> hclassTreeDescInfos_;
594     PGOProfilerHeader *header_ {nullptr};
595     std::shared_ptr<PGORecordPool> recordPool_;
596     std::shared_ptr<PGOProtoTransitionPool> protoTransitionPool_;
597     std::shared_ptr<PGOProfileTypePool> profileTypePool_;
598     mutable std::map<ApEntityId, ApEntityId> abcIdRemap_;
599     Mutex mutex_;
600 };
601 
602 class PGORecordSimpleInfos : public PGOContext {
603 public:
604     explicit PGORecordSimpleInfos(uint32_t threshold);
605 
606     ~PGORecordSimpleInfos() override;
607 
608     void Clear();
609 
610     void InitSections();
611 
612     bool Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId);
613 
614     template <typename Callback>
Update(const CString & abcNormalizedDesc,Callback callback)615     void Update(const CString &abcNormalizedDesc, Callback callback)
616     {
617         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
618         if (abcMethodIds == methodIds_.end()) {
619             return;
620         }
621         for (auto iter = abcMethodIds->second.begin(); iter != abcMethodIds->second.end(); iter++) {
622             auto recordName = iter->first;
623             auto methodIds = iter->second;
624             methodIds->Update(recordName, callback);
625         }
626     }
627 
628     template <typename Callback>
Update(const CString & abcNormalizedDesc,const CString & recordName,Callback callback)629     void Update(const CString &abcNormalizedDesc, const CString &recordName, Callback callback)
630     {
631         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
632         if (abcMethodIds == methodIds_.end()) {
633             return;
634         }
635         auto iter = abcMethodIds->second.find(recordName);
636         if (iter != abcMethodIds->second.end()) {
637             iter->second->Update(recordName, callback);
638         } else {
639             PGOMethodIdSet *methodIdSet = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
640             if (methodIdSet->Update(recordName, callback)) {
641                 abcMethodIds->second.emplace(recordName, methodIdSet);
642             } else {
643                 nativeAreaAllocator_.Delete(methodIdSet);
644             }
645         }
646     }
647 
648     template <typename Callback>
GetTypeInfo(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,Callback callback)649     void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName,
650                      Callback callback)
651     {
652         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
653         if (abcMethodIds == methodIds_.end()) {
654             return;
655         }
656         auto iter = abcMethodIds->second.find(recordName);
657         if (iter != abcMethodIds->second.end()) {
658             iter->second->GetTypeInfo(methodName, callback);
659         }
660     }
661 
662     template <typename Callback>
GetTypeInfo(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,uint32_t checksum,Callback callback)663     void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName,
664                      uint32_t checksum, Callback callback)
665     {
666         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
667         if (abcMethodIds == methodIds_.end()) {
668             return;
669         }
670         auto iter = abcMethodIds->second.find(recordName);
671         if (iter != abcMethodIds->second.end()) {
672             iter->second->GetTypeInfo(methodName, checksum, callback);
673         }
674     }
675 
GetProtoTransitionPool()676     std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const
677     {
678         return protoTransitionPool_;
679     }
680 
GetHClassTreeDesc(PGOSampleType profileType,PGOHClassTreeDesc ** desc)681     bool GetHClassTreeDesc(PGOSampleType profileType, PGOHClassTreeDesc **desc) const
682     {
683         auto iter = hclassTreeDescInfos_.find(PGOHClassTreeDesc(profileType.GetProfileType()));
684         if (iter != hclassTreeDescInfos_.end()) {
685             *desc = &(const_cast<PGOHClassTreeDesc &>(*iter));
686             return true;
687         }
688         return false;
689     }
690 
691     template <typename Callback>
IterateHClassTreeDesc(Callback callback)692     bool IterateHClassTreeDesc(Callback callback) const
693     {
694         for (auto treeDescInfo : hclassTreeDescInfos_) {
695             callback(&treeDescInfo);
696         }
697         return true;
698     }
699 
700     template <typename Callback>
IterateProtoTransitionPool(Callback callback)701     bool IterateProtoTransitionPool(Callback callback) const
702     {
703         protoTransitionPool_->Iterate(callback);
704         return true;
705     }
706 
MatchAndMarkMethod(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,EntityId methodId)707     void MatchAndMarkMethod(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName,
708                             EntityId methodId)
709     {
710         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
711         if (abcMethodIds == methodIds_.end()) {
712             return;
713         }
714         auto iter = abcMethodIds->second.find(recordName);
715         if (iter != abcMethodIds->second.end()) {
716             return iter->second->MatchAndMarkMethod(methodName, methodId);
717         }
718     }
719 
GetMismatchResult(const CString & abcNormalizedDesc,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet)720     void GetMismatchResult(const CString &abcNormalizedDesc, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount,
721                            std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
722     {
723         auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
724         if (abcMethodIds == methodIds_.end()) {
725             return;
726         }
727         for (const auto &methodId : abcMethodIds->second) {
728             methodId.second->GetMismatchResult(methodId.first, totalMethodCount, mismatchMethodCount,
729                                                mismatchMethodSet);
730         }
731     }
732 
733     void ParseFromBinary(void *buffer, PGOProfilerHeader *const header, std::shared_ptr<PGOAbcFilePool> &abcFilePool);
734 
735     void Merge(const PGORecordSimpleInfos &simpleInfos);
736 
GetProfileTypePool()737     std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
738     {
739         return profileTypePool_;
740     }
741 
GetHotnessThreshold()742     uint32_t GetHotnessThreshold() const override
743     {
744         return hotnessThreshold_;
745     }
746 
GetHeader()747     PGOProfilerHeader *GetHeader() const override
748     {
749         return header_;
750     }
751 
SupportElementsKind()752     bool SupportElementsKind() const override
753     {
754         ASSERT(header_ != nullptr);
755         return header_->SupportElementsKind();
756     }
757 
SupportElementsTrackInfo()758     bool SupportElementsTrackInfo() const override
759     {
760         ASSERT(header_ != nullptr);
761         return header_->SupportElementsTrackInfo();
762     }
763 
ResetAbcIdRemap()764     void ResetAbcIdRemap() const override
765     {
766         abcIdRemap_.clear();
767     }
768 
GetAbcIdRemap()769     const std::map<ApEntityId, ApEntityId> &GetAbcIdRemap() const override
770     {
771         return abcIdRemap_;
772     }
773 
AddAbcIdRemap(ApEntityId oldId,ApEntityId newId)774     void AddAbcIdRemap(ApEntityId oldId, ApEntityId newId) const override
775     {
776         abcIdRemap_[oldId] = newId;
777     }
778 
779     NO_COPY_SEMANTIC(PGORecordSimpleInfos);
780     NO_MOVE_SEMANTIC(PGORecordSimpleInfos);
781 
782 private:
783     bool ParseFromBinaryForLayout(void **buffer);
784 
785     uint32_t hotnessThreshold_ {2};
786     NativeAreaAllocator nativeAreaAllocator_;
787     std::unique_ptr<Chunk> chunk_;
788     CUnorderedMap<CString, CUnorderedMap<CString, PGOMethodIdSet *>> methodIds_;
789     PGOProfilerHeader *header_ {nullptr};
790     // std::list<std::weak_ptr<PGOFileSectionInterface>> apSectionList_;
791     std::shared_ptr<PGORecordPool> recordPool_;
792     std::shared_ptr<PGOProtoTransitionPool> protoTransitionPool_;
793     std::shared_ptr<PGOProfileTypePool> profileTypePool_;
794     std::set<PGOHClassTreeDesc> hclassTreeDescInfos_;
795     mutable std::map<ApEntityId, ApEntityId> abcIdRemap_;
796 };
797 } // namespace panda::ecmascript::pgo
798 #endif // ECMASCRIPT_PGO_PROFILER_INFO_H
799