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