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
49namespace panda::ecmascript::pgo {
50class SaveTask;
51class PGOContext;
52
53class PGOPandaFileInfos {
54public:
55    void Sample(uint32_t checksum)
56    {
57        fileInfos_.emplace(checksum);
58    }
59
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
76private:
77    class FileInfo {
78    public:
79        FileInfo() = default;
80        FileInfo(uint32_t checksum) : size_(LastSize()), checksum_(checksum) {}
81
82        static size_t LastSize()
83        {
84            return sizeof(FileInfo);
85        }
86
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
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
111class PGOMethodInfo {
112public:
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
120    explicit PGOMethodInfo(PGOMethodId id) : id_(id) {}
121
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
138    static int32_t Size(uint32_t length)
139    {
140        return sizeof(PGOMethodInfo) + AlignUp(length, GetAlignmentInBytes(ALIGN_SIZE));
141    }
142
143    int32_t Size() const
144    {
145        return size_;
146    }
147
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
160    void IncreaseCount()
161    {
162        count_++;
163    }
164
165    void ClearCount()
166    {
167        count_ = 0;
168    }
169
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
180    PGOMethodId GetMethodId() const
181    {
182        return id_;
183    }
184
185    uint32_t GetCount() const
186    {
187        return count_;
188    }
189
190    const char *GetMethodName() const
191    {
192        return &methodName_;
193    }
194
195    void SetSampleMode(SampleMode mode)
196    {
197        if (mode_ == SampleMode::HOTNESS_MODE) {
198            return;
199        }
200        mode_ = mode;
201    }
202
203    SampleMode GetSampleMode() const
204    {
205        return mode_;
206    }
207
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
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
243private:
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
251class PGODecodeMethodInfo {
252public:
253    explicit PGODecodeMethodInfo(PGOMethodId id) : methodId_(id) {}
254
255    PGOMethodId GetMethodId() const
256    {
257        return methodId_;
258    }
259
260    PGOMethodTypeSet &GetPGOMethodTypeSet()
261    {
262        return pgoMethodTypeSet_;
263    }
264
265    void Merge(const PGODecodeMethodInfo &from);
266
267private:
268    PGOMethodId methodId_ {0};
269    PGOMethodTypeSet pgoMethodTypeSet_ {};
270};
271
272class PGOMethodInfoMap {
273public:
274    PGOMethodInfoMap() = default;
275
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
302    const CMap<PGOMethodId, PGOMethodInfo *> &GetMethodInfos() const
303    {
304        return methodInfos_;
305    }
306
307    NO_COPY_SEMANTIC(PGOMethodInfoMap);
308    NO_MOVE_SEMANTIC(PGOMethodInfoMap);
309
310private:
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
319class PGOMethodIdSet {
320public:
321    explicit PGOMethodIdSet(Chunk* chunk): chunk_(chunk), methodInfoMap_(chunk) {};
322    ~PGOMethodIdSet() = default;
323
324    void Clear()
325    {
326        candidateSet_.clear();
327        for (auto &methodNameSet : methodInfoMap_) {
328            methodNameSet.second.Clear();
329        }
330        methodInfoMap_.clear();
331    }
332
333    bool Match(EntityId methodId)
334    {
335        return candidateSet_.find(methodId) != candidateSet_.end();
336    }
337
338    template <typename 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>
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>
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
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:
389        explicit PGOMethodNameSet(Chunk* chunk): methodMap_(chunk) {};
390        void SetMatch()
391        {
392            methodNameMatch_ = true;
393        }
394
395        bool IsMatch() const
396        {
397            return methodNameMatch_;
398        }
399
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
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
425        PGODecodeMethodInfo *GetFirstMethodInfo()
426        {
427            if (methodMap_.empty()) {
428                return nullptr;
429            }
430            return &(methodMap_.begin()->second);
431        }
432
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
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
455private:
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
461class PGORecordDetailInfos : public PGOContext {
462public:
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
495    const CMap<ProfileType, PGOMethodInfoMap *> &GetRecordInfos() const
496    {
497        return recordInfos_;
498    }
499
500    std::shared_ptr<PGORecordPool> GetRecordPool() const
501    {
502        return recordPool_;
503    }
504
505    std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
506    {
507        return profileTypePool_;
508    }
509
510    std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const
511    {
512        return protoTransitionPool_;
513    }
514
515    uint32_t GetHotnessThreshold() const override
516    {
517        return hotnessThreshold_;
518    }
519
520    PGOProfilerHeader *GetHeader() const override
521    {
522        return header_;
523    }
524
525    bool SupportElementsKind() const override
526    {
527        ASSERT(header_ != nullptr);
528        return header_->SupportElementsKind();
529    }
530
531    bool SupportElementsTrackInfo() const override
532    {
533        ASSERT(header_ != nullptr);
534        return header_->SupportElementsTrackInfo();
535    }
536
537    void ResetAbcIdRemap() const override
538    {
539        abcIdRemap_.clear();
540    }
541
542    void AddAbcIdRemap(ApEntityId oldId, ApEntityId newId) const override
543    {
544        abcIdRemap_[oldId] = newId;
545    }
546
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
555private:
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
572class PGORecordSimpleInfos : public PGOContext {
573public:
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>
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>
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>
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>
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
646    std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const
647    {
648        return protoTransitionPool_;
649    }
650
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>
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>
671    bool IterateProtoTransitionPool(Callback callback) const
672    {
673        protoTransitionPool_->Iterate(callback);
674        return true;
675    }
676
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
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
707    std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override
708    {
709        return profileTypePool_;
710    }
711
712    uint32_t GetHotnessThreshold() const override
713    {
714        return hotnessThreshold_;
715    }
716
717    PGOProfilerHeader *GetHeader() const override
718    {
719        return header_;
720    }
721
722    bool SupportElementsKind() const override
723    {
724        ASSERT(header_ != nullptr);
725        return header_->SupportElementsKind();
726    }
727
728    bool SupportElementsTrackInfo() const override
729    {
730        ASSERT(header_ != nullptr);
731        return header_->SupportElementsTrackInfo();
732    }
733
734    void ResetAbcIdRemap() const override
735    {
736        abcIdRemap_.clear();
737    }
738
739    const std::map<ApEntityId, ApEntityId> &GetAbcIdRemap() const override
740    {
741        return abcIdRemap_;
742    }
743
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
752private:
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