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