• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "ecmascript/pgo_profiler/pgo_profiler_info.h"
17 #include <cstdint>
18 #include <fstream>
19 #include <iomanip>
20 #include <memory>
21 #include <utility>
22 
23 #include "ecmascript/base/bit_helper.h"
24 #include "ecmascript/base/file_header.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/jspandafile/js_pandafile.h"
27 #include "ecmascript/jspandafile/method_literal.h"
28 #include "ecmascript/log.h"
29 #include "ecmascript/log_wrapper.h"
30 #include "ecmascript/mem/c_string.h"
31 #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
32 #include "ecmascript/pgo_profiler/ap_file/pgo_method_type_set.h"
33 #include "ecmascript/pgo_profiler/ap_file/pgo_profile_type_pool.h"
34 #include "ecmascript/pgo_profiler/ap_file/pgo_record_pool.h"
35 #include "ecmascript/pgo_profiler/pgo_context.h"
36 #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
37 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
38 #include "ecmascript/pgo_profiler/pgo_utils.h"
39 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
40 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
41 #include "macros.h"
42 #include "securec.h"
43 
44 namespace panda::ecmascript::pgo {
45 using StringHelper = base::StringHelper;
ParseFromBinary(void * buffer,SectionInfo * const info)46 void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
47 {
48     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
49     for (uint32_t i = 0; i < info->number_; i++) {
50         fileInfos_.emplace(*base::ReadBufferInSize<FileInfo>(&addr));
51     }
52     LOG_ECMA(DEBUG) << "Profiler panda file count:" << info->number_;
53 }
54 
ProcessToBinary(std::fstream & fileStream,SectionInfo * info) const55 void PGOPandaFileInfos::ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const
56 {
57     fileStream.seekp(info->offset_);
58     info->number_ = fileInfos_.size();
59     for (auto localInfo : fileInfos_) {
60         fileStream.write(reinterpret_cast<char *>(&localInfo), localInfo.Size());
61     }
62     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
63 }
64 
Merge(const PGOPandaFileInfos & pandaFileInfos)65 void PGOPandaFileInfos::Merge(const PGOPandaFileInfos &pandaFileInfos)
66 {
67     for (const auto &info : pandaFileInfos.fileInfos_) {
68         fileInfos_.emplace(info.GetChecksum());
69     }
70 }
71 
VerifyChecksum(const PGOPandaFileInfos & pandaFileInfos,const std::string & base,const std::string & incoming) const72 bool PGOPandaFileInfos::VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
73                                        const std::string &incoming) const
74 {
75     std::set<FileInfo> unionChecksum;
76     set_union(fileInfos_.begin(), fileInfos_.end(), pandaFileInfos.fileInfos_.begin(), pandaFileInfos.fileInfos_.end(),
77               inserter(unionChecksum, unionChecksum.begin()));
78     if (!fileInfos_.empty() && unionChecksum.empty()) {
79         LOG_ECMA(ERROR) << "First AP file(" << base << ") and the incoming file(" << incoming
80                         << ") do not come from the same abc file, skip merge the incoming file.";
81         return false;
82     }
83     return true;
84 }
85 
ParseFromText(std::ifstream & stream)86 bool PGOPandaFileInfos::ParseFromText(std::ifstream &stream)
87 {
88     std::string pandaFileInfo;
89     while (std::getline(stream, pandaFileInfo)) {
90         if (pandaFileInfo.empty()) {
91             continue;
92         }
93 
94         size_t start = pandaFileInfo.find_first_of(DumpUtils::ARRAY_START);
95         size_t end = pandaFileInfo.find_last_of(DumpUtils::ARRAY_END);
96         if (start == std::string::npos || end == std::string::npos || start > end) {
97             return false;
98         }
99         auto content = pandaFileInfo.substr(start + 1, end - (start + 1) - 1);
100         std::vector<std::string> infos = StringHelper::SplitString(content, DumpUtils::BLOCK_SEPARATOR);
101         for (auto checksum : infos) {
102             uint32_t result;
103             if (!StringHelper::StrToUInt32(checksum.c_str(), &result)) {
104                 LOG_ECMA(ERROR) << "checksum: " << checksum << " parse failed";
105                 return false;
106             }
107             Sample(result);
108         }
109         return true;
110     }
111     return true;
112 }
113 
ProcessToText(std::ofstream & stream) const114 void PGOPandaFileInfos::ProcessToText(std::ofstream &stream) const
115 {
116     std::string pandaFileInfo = DumpUtils::NEW_LINE + DumpUtils::PANDA_FILE_INFO_HEADER;
117     bool isFirst = true;
118     for (auto &info : fileInfos_) {
119         if (!isFirst) {
120             pandaFileInfo += DumpUtils::BLOCK_SEPARATOR + DumpUtils::SPACE;
121         } else {
122             isFirst = false;
123         }
124         pandaFileInfo += std::to_string(info.GetChecksum());
125     }
126 
127     pandaFileInfo += (DumpUtils::SPACE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
128     stream << pandaFileInfo;
129 }
130 
Checksum(uint32_t checksum) const131 bool PGOPandaFileInfos::Checksum(uint32_t checksum) const
132 {
133     if (fileInfos_.find(checksum) == fileInfos_.end()) {
134         LOG_ECMA(ERROR) << "Checksum verification failed. Please ensure that the .abc and .ap match.";
135         return false;
136     }
137     return true;
138 }
139 
ProcessToText(std::string & text) const140 void PGOMethodInfo::ProcessToText(std::string &text) const
141 {
142     text += std::to_string(GetMethodId().GetOffset());
143     text += DumpUtils::ELEMENT_SEPARATOR;
144     text += std::to_string(GetCount());
145     text += DumpUtils::ELEMENT_SEPARATOR;
146     text += GetSampleModeToString();
147     text += DumpUtils::ELEMENT_SEPARATOR;
148     text += GetMethodName();
149 }
150 
ParseFromText(const std::string & infoString)151 std::vector<std::string> PGOMethodInfo::ParseFromText(const std::string &infoString)
152 {
153     std::vector<std::string> infoStrings = StringHelper::SplitString(infoString, DumpUtils::ELEMENT_SEPARATOR);
154     return infoStrings;
155 }
156 
CalcChecksum(const char * name,const uint8_t * byteCodeArray,uint32_t byteCodeLength)157 uint32_t PGOMethodInfo::CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength)
158 {
159     uint32_t checksum = 0;
160     if (byteCodeArray != nullptr) {
161         checksum = CalcOpCodeChecksum(byteCodeArray, byteCodeLength);
162     }
163 
164     if (name != nullptr) {
165         checksum = adler32(checksum, reinterpret_cast<const Bytef *>(name), strlen(name));
166     }
167     return checksum;
168 }
169 
CalcOpCodeChecksum(const uint8_t * byteCodeArray,uint32_t byteCodeLength)170 uint32_t PGOMethodInfo::CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength)
171 {
172     uint32_t checksum = 0;
173     BytecodeInstruction bcIns(byteCodeArray);
174     auto bcInsLast = bcIns.JumpTo(byteCodeLength);
175     while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
176         auto opCode = bcIns.GetOpcode();
177         checksum = adler32(checksum, reinterpret_cast<const Bytef *>(&opCode), sizeof(decltype(opCode)));
178         bcIns = bcIns.GetNext();
179     }
180     return checksum;
181 }
182 
AddMethod(NativeAreaAllocator * allocator,Method * jsMethod,SampleMode mode)183 bool PGOMethodInfoMap::AddMethod(NativeAreaAllocator *allocator, Method *jsMethod, SampleMode mode)
184 {
185     PGOMethodId methodId(jsMethod->GetMethodId());
186     auto result = methodInfos_.find(methodId);
187     if (result != methodInfos_.end()) {
188         auto info = result->second;
189         info->IncreaseCount();
190         info->SetSampleMode(mode);
191         return false;
192     } else {
193         CString methodName = jsMethod->GetMethodName();
194         size_t strlen = methodName.size();
195         size_t size = static_cast<size_t>(PGOMethodInfo::Size(strlen));
196         void *infoAddr = allocator->Allocate(size);
197         auto info = new (infoAddr) PGOMethodInfo(methodId, 0, mode, methodName.c_str());
198         info->IncreaseCount();
199         methodInfos_.emplace(methodId, info);
200         auto checksum = PGOMethodInfo::CalcChecksum(jsMethod->GetMethodName(), jsMethod->GetBytecodeArray(),
201                                                     jsMethod->GetCodeSize());
202         methodsChecksum_.emplace(methodId, checksum);
203         return true;
204     }
205 }
206 
GetOrInsertMethodTypeSet(Chunk * chunk,PGOMethodId methodId)207 PGOMethodTypeSet *PGOMethodInfoMap::GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId)
208 {
209     auto typeInfoSetIter = methodTypeInfos_.find(methodId);
210     if (typeInfoSetIter != methodTypeInfos_.end()) {
211         return typeInfoSetIter->second;
212     } else {
213         auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
214         methodTypeInfos_.emplace(methodId, typeInfoSet);
215         return typeInfoSet;
216     }
217 }
218 
AddType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)219 bool PGOMethodInfoMap::AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
220 {
221     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
222     ASSERT(typeInfoSet != nullptr);
223     typeInfoSet->AddType(offset, type);
224     return true;
225 }
226 
AddCallTargetType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)227 bool PGOMethodInfoMap::AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
228 {
229     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
230     ASSERT(typeInfoSet != nullptr);
231     typeInfoSet->AddCallTargetType(offset, type);
232     return true;
233 }
234 
AddObjectInfo(Chunk * chunk,PGOMethodId methodId,int32_t offset,const PGOObjectInfo & info)235 bool PGOMethodInfoMap::AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info)
236 {
237     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
238     ASSERT(typeInfoSet != nullptr);
239     typeInfoSet->AddObjectInfo(offset, info);
240     return true;
241 }
242 
AddDefine(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGODefineOpType type)243 bool PGOMethodInfoMap::AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGODefineOpType type)
244 {
245     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
246     ASSERT(typeInfoSet != nullptr);
247     typeInfoSet->AddDefine(offset, type);
248     return true;
249 }
250 
Merge(Chunk * chunk,PGOMethodInfoMap * methodInfos)251 void PGOMethodInfoMap::Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos)
252 {
253     for (auto iter = methodInfos->methodInfos_.begin(); iter != methodInfos->methodInfos_.end(); iter++) {
254         auto methodId = iter->first;
255         auto fromMethodInfo = iter->second;
256 
257         auto result = methodInfos_.find(methodId);
258         if (result != methodInfos_.end()) {
259             auto toMethodInfo = result->second;
260             toMethodInfo->Merge(fromMethodInfo);
261         } else {
262             size_t len = strlen(fromMethodInfo->GetMethodName());
263             size_t size = static_cast<size_t>(PGOMethodInfo::Size(len));
264             void *infoAddr = chunk->Allocate(size);
265             auto newMethodInfo = new (infoAddr) PGOMethodInfo(
266                 methodId, fromMethodInfo->GetCount(), fromMethodInfo->GetSampleMode(), fromMethodInfo->GetMethodName());
267             methodInfos_.emplace(methodId, newMethodInfo);
268         }
269         fromMethodInfo->ClearCount();
270     }
271 
272     for (auto iter = methodInfos->methodTypeInfos_.begin(); iter != methodInfos->methodTypeInfos_.end(); iter++) {
273         auto methodId = iter->first;
274         auto fromTypeInfo = iter->second;
275 
276         auto result = methodTypeInfos_.find(methodId);
277         if (result != methodTypeInfos_.end()) {
278             auto toTypeInfo = result->second;
279             toTypeInfo->Merge(fromTypeInfo);
280         } else {
281             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
282             typeInfoSet->Merge(fromTypeInfo);
283             methodTypeInfos_.emplace(methodId, typeInfoSet);
284         }
285     }
286 
287     for (auto iter = methodInfos->methodsChecksum_.begin(); iter != methodInfos->methodsChecksum_.end(); iter++) {
288         auto methodId = iter->first;
289         auto result = methodsChecksum_.find(methodId);
290         if (result == methodsChecksum_.end()) {
291             methodsChecksum_.emplace(methodId, iter->second);
292         }
293     }
294 }
295 
ParseFromBinary(Chunk * chunk,PGOContext & context,void ** buffer)296 bool PGOMethodInfoMap::ParseFromBinary(Chunk *chunk, PGOContext &context, void **buffer)
297 {
298     PGOProfilerHeader *const header = context.GetHeader();
299     ASSERT(header != nullptr);
300     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
301     for (uint32_t j = 0; j < secInfo.number_; j++) {
302         PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
303         if (info->IsFilter(context.GetHotnessThreshold())) {
304             if (header->SupportMethodChecksum()) {
305                 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
306             }
307             if (header->SupportType()) {
308                 PGOMethodTypeSet::SkipFromBinary(buffer);
309             }
310             continue;
311         }
312         methodInfos_.emplace(info->GetMethodId(), info);
313         LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << DumpUtils::ELEMENT_SEPARATOR << info->GetCount()
314                         << DumpUtils::ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
315                         << DumpUtils::ELEMENT_SEPARATOR << info->GetMethodName();
316         if (header->SupportMethodChecksum()) {
317             auto checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
318             methodsChecksum_.emplace(info->GetMethodId(), checksum);
319         }
320         if (header->SupportType()) {
321             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
322             typeInfoSet->ParseFromBinary(context, buffer);
323             methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
324         }
325     }
326     return !methodInfos_.empty();
327 }
328 
ProcessToBinary(PGOContext & context,ProfileTypeRef recordProfileRef,const SaveTask * task,std::fstream & stream,PGOProfilerHeader * const header) const329 bool PGOMethodInfoMap::ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task,
330                                        std::fstream &stream, PGOProfilerHeader *const header) const
331 {
332     SectionInfo secInfo;
333     std::stringstream methodStream;
334     for (auto iter = methodInfos_.begin(); iter != methodInfos_.end(); iter++) {
335         LOG_ECMA(DEBUG) << "Method:" << iter->first << DumpUtils::ELEMENT_SEPARATOR << iter->second->GetCount()
336                         << DumpUtils::ELEMENT_SEPARATOR
337                         << std::to_string(static_cast<int>(iter->second->GetSampleMode()))
338                         << DumpUtils::ELEMENT_SEPARATOR << iter->second->GetMethodName();
339         if (task && task->IsTerminate()) {
340             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
341             return false;
342         }
343         auto curMethodInfo = iter->second;
344         if (curMethodInfo->IsFilter(context.GetHotnessThreshold())) {
345             continue;
346         }
347         methodStream.write(reinterpret_cast<char *>(curMethodInfo), curMethodInfo->Size());
348         if (header->SupportMethodChecksum()) {
349             auto checksumIter = methodsChecksum_.find(curMethodInfo->GetMethodId());
350             uint32_t checksum = 0;
351             if (checksumIter != methodsChecksum_.end()) {
352                 checksum = checksumIter->second;
353             }
354             methodStream.write(reinterpret_cast<char *>(&checksum), sizeof(uint32_t));
355         }
356         if (header->SupportType()) {
357             auto typeInfoIter = methodTypeInfos_.find(curMethodInfo->GetMethodId());
358             if (typeInfoIter != methodTypeInfos_.end()) {
359                 typeInfoIter->second->ProcessToBinary(context, methodStream);
360             } else {
361                 uint32_t number = 0;
362                 methodStream.write(reinterpret_cast<char *>(&number), sizeof(uint32_t));
363             }
364         }
365         secInfo.number_++;
366     }
367     if (secInfo.number_ > 0) {
368         secInfo.offset_ = sizeof(SectionInfo);
369         secInfo.size_ = static_cast<uint32_t>(methodStream.tellp());
370         stream.write(reinterpret_cast<char *>(&recordProfileRef), sizeof(uint32_t));
371         stream.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo));
372         stream << methodStream.rdbuf();
373         return true;
374     }
375     return false;
376 }
377 
ParseFromText(Chunk * chunk,uint32_t threshold,const std::vector<std::string> & content)378 bool PGOMethodInfoMap::ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content)
379 {
380     for (auto infoString : content) {
381         std::vector<std::string> infoStrings = PGOMethodInfo::ParseFromText(infoString);
382         if (infoStrings.size() < PGOMethodInfo::METHOD_INFO_COUNT) {
383             LOG_ECMA(ERROR) << "method info:" << infoString << " format error";
384             return false;
385         }
386         uint32_t count;
387         if (!StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX].c_str(), &count)) {
388             LOG_ECMA(ERROR) << "count: " << infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX] << " parse failed";
389             return false;
390         }
391         SampleMode mode;
392         if (!PGOMethodInfo::GetSampleMode(infoStrings[PGOMethodInfo::METHOD_MODE_INDEX], mode)) {
393             LOG_ECMA(ERROR) << "mode: " << infoStrings[PGOMethodInfo::METHOD_MODE_INDEX] << " parse failed";
394             return false;
395         }
396         if (count < threshold && mode == SampleMode::CALL_MODE) {
397             return true;
398         }
399         uint32_t methodId;
400         if (!StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_ID_INDEX].c_str(), &methodId)) {
401             LOG_ECMA(ERROR) << "method id: " << infoStrings[PGOMethodInfo::METHOD_ID_INDEX] << " parse failed";
402             return false;
403         }
404         std::string methodName = infoStrings[PGOMethodInfo::METHOD_NAME_INDEX];
405 
406         size_t len = methodName.size();
407         void *infoAddr = chunk->Allocate(PGOMethodInfo::Size(len));
408         auto info = new (infoAddr) PGOMethodInfo(PGOMethodId(methodId), count, mode, methodName.c_str());
409         methodInfos_.emplace(methodId, info);
410 
411         // Parse Type Info
412         if (infoStrings.size() <= PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX) {
413             continue;
414         }
415         std::string typeInfos = infoStrings[PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX];
416         if (!typeInfos.empty()) {
417             size_t start = typeInfos.find_first_of(DumpUtils::ARRAY_START);
418             size_t end = typeInfos.find_last_of(DumpUtils::ARRAY_END);
419             if (start == std::string::npos || end == std::string::npos || start > end) {
420                 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
421                 return false;
422             }
423             auto typeContent = typeInfos.substr(start + 1, end - (start + 1) - 1);
424             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
425             if (!typeInfoSet->ParseFromText(typeContent)) {
426                 // delete by chunk
427                 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
428                 return false;
429             }
430             methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
431         }
432     }
433 
434     return true;
435 }
436 
ProcessToText(uint32_t threshold,const CString & recordName,std::ofstream & stream) const437 void PGOMethodInfoMap::ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const
438 {
439     std::string profilerString;
440     bool isFirst = true;
441     for (auto methodInfoIter : methodInfos_) {
442         auto methodInfo = methodInfoIter.second;
443         if (methodInfo->IsFilter(threshold)) {
444             continue;
445         }
446         if (isFirst) {
447             profilerString += DumpUtils::NEW_LINE;
448             profilerString += recordName;
449             profilerString += DumpUtils::BLOCK_AND_ARRAY_START;
450             isFirst = false;
451         } else {
452             profilerString += DumpUtils::BLOCK_SEPARATOR + DumpUtils::SPACE;
453         }
454         methodInfo->ProcessToText(profilerString);
455         profilerString += DumpUtils::ELEMENT_SEPARATOR;
456         auto checksumIter = methodsChecksum_.find(methodInfo->GetMethodId());
457         if (checksumIter != methodsChecksum_.end()) {
458             std::stringstream parseStream;
459             parseStream << std::internal << std::setfill('0') << std::showbase
460                         << std::setw(DumpUtils::HEX_FORMAT_WIDTH_FOR_32BITS) << std::hex << checksumIter->second
461                         << DumpUtils::ELEMENT_SEPARATOR;
462             profilerString += parseStream.str();
463         }
464         auto iter = methodTypeInfos_.find(methodInfo->GetMethodId());
465         if (iter != methodTypeInfos_.end()) {
466             iter->second->ProcessToText(profilerString);
467         }
468     }
469     if (!isFirst) {
470         profilerString += (DumpUtils::SPACE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
471         stream << profilerString;
472     }
473 }
474 
ParseFromBinary(PGOContext & context,void ** buffer)475 bool PGOMethodIdSet::ParseFromBinary(PGOContext &context, void **buffer)
476 {
477     PGOProfilerHeader *const header = context.GetHeader();
478     ASSERT(header != nullptr);
479     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
480     for (uint32_t j = 0; j < secInfo.number_; j++) {
481         PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
482         if (info->IsFilter(context.GetHotnessThreshold())) {
483             if (header->SupportMethodChecksum()) {
484                 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
485             }
486             if (header->SupportType()) {
487                 PGOMethodTypeSet::SkipFromBinary(buffer);
488             }
489             continue;
490         }
491         uint32_t checksum = 0;
492         if (header->SupportMethodChecksum()) {
493             checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
494         }
495         auto ret = methodInfoMap_.try_emplace(info->GetMethodName(), chunk_);
496         auto methodNameSetIter = ret.first;
497         auto &methodInfo = methodNameSetIter->second.GetOrCreateMethodInfo(checksum, info->GetMethodId());
498         LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << DumpUtils::ELEMENT_SEPARATOR << info->GetCount()
499                         << DumpUtils::ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
500                         << DumpUtils::ELEMENT_SEPARATOR << info->GetMethodName();
501         if (header->SupportType()) {
502             methodInfo.GetPGOMethodTypeSet().ParseFromBinary(context, buffer);
503         }
504     }
505 
506     return !methodInfoMap_.empty();
507 }
508 
GetMismatchResult(const CString & recordName,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet) const509 void PGOMethodIdSet::GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount,
510                                        uint32_t &mismatchMethodCount,
511                                        std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
512 {
513     totalMethodCount += methodInfoMap_.size();
514     for (const auto &methodNameSet : methodInfoMap_) {
515         if (methodNameSet.second.IsMatch()) {
516             continue;
517         }
518         auto info = std::make_pair(methodNameSet.first, recordName);
519         mismatchMethodSet.emplace(info);
520         mismatchMethodCount++;
521     }
522 }
523 
Merge(const PGOMethodIdSet & from)524 void PGOMethodIdSet::Merge(const PGOMethodIdSet &from)
525 {
526     for (const auto &methodNameSet : from.methodInfoMap_) {
527         auto iter = methodInfoMap_.find(methodNameSet.first);
528         if (iter == methodInfoMap_.end()) {
529             auto ret = methodInfoMap_.try_emplace(methodNameSet.first, chunk_);
530             iter = ret.first;
531         }
532         const_cast<PGOMethodNameSet &>(iter->second).Merge(methodNameSet.second);
533     }
534 }
535 
Merge(const PGODecodeMethodInfo & from)536 void PGODecodeMethodInfo::Merge(const PGODecodeMethodInfo &from)
537 {
538     ASSERT(methodId_.IsValid() && from.methodId_.IsValid());
539     if (!(methodId_ == from.methodId_)) {
540         LOG_ECMA(ERROR) << "MethodId not match. " << methodId_ << " vs " << from.methodId_;
541         return;
542     }
543     pgoMethodTypeSet_.Merge(&from.pgoMethodTypeSet_);
544 }
545 
PGORecordDetailInfos(uint32_t hotnessThreshold)546 PGORecordDetailInfos::PGORecordDetailInfos(uint32_t hotnessThreshold) : hotnessThreshold_(hotnessThreshold)
547 {
548     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
549     InitSections();
550 };
551 
~PGORecordDetailInfos()552 PGORecordDetailInfos::~PGORecordDetailInfos()
553 {
554     Clear();
555 }
556 
GetMethodInfoMap(ProfileType recordProfileType)557 PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(ProfileType recordProfileType)
558 {
559     auto iter = recordInfos_.find(recordProfileType);
560     if (iter != recordInfos_.end()) {
561         return iter->second;
562     } else {
563         auto curMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
564         recordInfos_.emplace(recordProfileType, curMethodInfos);
565         return curMethodInfos;
566     }
567 }
568 
AddMethod(ProfileType recordProfileType,Method * jsMethod,SampleMode mode)569 bool PGORecordDetailInfos::AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode)
570 {
571     auto curMethodInfos = GetMethodInfoMap(recordProfileType);
572     ASSERT(curMethodInfos != nullptr);
573     ASSERT(jsMethod != nullptr);
574     return curMethodInfos->AddMethod(&nativeAreaAllocator_, jsMethod, mode);
575 }
576 
AddType(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGOSampleType type)577 bool PGORecordDetailInfos::AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
578                                    PGOSampleType type)
579 {
580     auto curMethodInfos = GetMethodInfoMap(recordProfileType);
581     ASSERT(curMethodInfos != nullptr);
582     return curMethodInfos->AddType(chunk_.get(), methodId, offset, type);
583 }
584 
AddCallTargetType(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGOSampleType type)585 bool PGORecordDetailInfos::AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset,
586                                              PGOSampleType type)
587 {
588     auto curMethodInfos = GetMethodInfoMap(recordProfileType);
589     ASSERT(curMethodInfos != nullptr);
590     return curMethodInfos->AddCallTargetType(chunk_.get(), methodId, offset, type);
591 }
592 
AddObjectInfo(ProfileType recordProfileType,EntityId methodId,int32_t offset,const PGOObjectInfo & info)593 bool PGORecordDetailInfos::AddObjectInfo(
594     ProfileType recordProfileType, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
595 {
596     auto curMethodInfos = GetMethodInfoMap(recordProfileType);
597     ASSERT(curMethodInfos != nullptr);
598     return curMethodInfos->AddObjectInfo(chunk_.get(), methodId, offset, info);
599 }
600 
AddDefine(ProfileType recordProfileType,PGOMethodId methodId,int32_t offset,PGODefineOpType type)601 bool PGORecordDetailInfos::AddDefine(
602     ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGODefineOpType type)
603 {
604     auto curMethodInfos = GetMethodInfoMap(recordProfileType);
605     ASSERT(curMethodInfos != nullptr);
606     curMethodInfos->AddDefine(chunk_.get(), methodId, offset, type);
607 
608     PGOHClassTreeDesc descInfo(type.GetProfileType());
609     auto iter = hclassTreeDescInfos_.find(descInfo);
610     if (iter == hclassTreeDescInfos_.end()) {
611         descInfo.SetProtoPt(type.GetProtoTypePt());
612         hclassTreeDescInfos_.emplace(descInfo);
613     } else {
614         const_cast<PGOHClassTreeDesc &>(*iter).SetProtoPt(type.GetProtoTypePt());
615     }
616     return true;
617 }
618 
AddRootLayout(JSTaggedType hclass,ProfileType rootType)619 bool PGORecordDetailInfos::AddRootLayout(JSTaggedType hclass, ProfileType rootType)
620 {
621     PGOHClassTreeDesc descInfo(rootType);
622     auto iter = hclassTreeDescInfos_.find(descInfo);
623     if (iter != hclassTreeDescInfos_.end()) {
624         return const_cast<PGOHClassTreeDesc &>(*iter).DumpForRoot(hclass, rootType);
625     } else {
626         if (!descInfo.DumpForRoot(hclass, rootType)) {
627             return false;
628         }
629         hclassTreeDescInfos_.emplace(descInfo);
630     }
631     return true;
632 }
633 
UpdateLayout(ProfileType rootType,JSTaggedType hclass,ProfileType curType)634 bool PGORecordDetailInfos::UpdateLayout(ProfileType rootType, JSTaggedType hclass, ProfileType curType)
635 {
636     PGOHClassTreeDesc descInfo(rootType);
637     auto iter = hclassTreeDescInfos_.find(descInfo);
638     if (iter != hclassTreeDescInfos_.end()) {
639         return const_cast<PGOHClassTreeDesc &>(*iter).UpdateLayout(hclass, curType);
640     } else {
641         if (!descInfo.UpdateLayout(hclass, curType)) {
642             return false;
643         }
644         hclassTreeDescInfos_.emplace(descInfo);
645         return false;
646     }
647     return true;
648 }
649 
UpdateTransitionLayout(ProfileType rootType,JSTaggedType parent,ProfileType parentType,JSTaggedType child,ProfileType childType)650 bool PGORecordDetailInfos::UpdateTransitionLayout(
651     ProfileType rootType, JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType)
652 {
653     PGOHClassTreeDesc descInfo(rootType);
654     auto iter = hclassTreeDescInfos_.find(descInfo);
655     if (iter != hclassTreeDescInfos_.end()) {
656         return const_cast<PGOHClassTreeDesc &>(*iter).UpdateForTransition(parent, parentType, child, childType);
657     } else {
658         if (!descInfo.UpdateForTransition(parent, parentType, child, childType)) {
659             return false;
660         }
661         hclassTreeDescInfos_.emplace(descInfo);
662     }
663     return true;
664 }
665 
AddRootPtType(ProfileType rootType,ProfileType ptType)666 void PGORecordDetailInfos::AddRootPtType(ProfileType rootType, ProfileType ptType)
667 {
668     PGOHClassTreeDesc descInfo(rootType);
669     auto iter = hclassTreeDescInfos_.find(descInfo);
670     if (iter != hclassTreeDescInfos_.end()) {
671         const_cast<PGOHClassTreeDesc &>(*iter).SetProtoPt(ptType);
672     } else {
673         descInfo.SetProtoPt(ptType);
674         hclassTreeDescInfos_.emplace(descInfo);
675     }
676 }
677 
IsDumped(ProfileType rootType,ProfileType curType) const678 bool PGORecordDetailInfos::IsDumped(ProfileType rootType, ProfileType curType) const
679 {
680     PGOHClassTreeDesc descInfo(rootType);
681     auto iter = hclassTreeDescInfos_.find(descInfo);
682     if (iter != hclassTreeDescInfos_.end()) {
683         return const_cast<PGOHClassTreeDesc &>(*iter).IsDumped(curType);
684     }
685     return false;
686 }
687 
Merge(const PGORecordDetailInfos & recordInfos)688 void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
689 {
690     CMap<ProfileType, PGOMethodInfoMap *> methodInfos = recordInfos.recordInfos_;
691     for (auto iter = methodInfos.begin(); iter != methodInfos.end(); iter++) {
692         auto recordType = iter->first;
693         auto fromMethodInfos = iter->second;
694 
695         auto recordInfosIter = recordInfos_.find(recordType);
696         PGOMethodInfoMap *toMethodInfos = nullptr;
697         if (recordInfosIter == recordInfos_.end()) {
698             toMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
699             recordInfos_.emplace(recordType, toMethodInfos);
700         } else {
701             toMethodInfos = recordInfosIter->second;
702         }
703 
704         toMethodInfos->Merge(chunk_.get(), fromMethodInfos);
705     }
706 
707     recordPool_->Merge(*recordInfos.recordPool_);
708     // Merge global layout desc infos to global method info map
709     std::set<PGOHClassTreeDesc> hclassTreeDescInfos = recordInfos.hclassTreeDescInfos_;
710     for (auto info = hclassTreeDescInfos.begin(); info != hclassTreeDescInfos.end();
711          info++) {
712         auto &fromInfo = *info;
713         auto result = hclassTreeDescInfos_.find(fromInfo);
714         if (result == hclassTreeDescInfos_.end()) {
715             PGOHClassTreeDesc descInfo(fromInfo.GetProfileType());
716             descInfo.SetProtoPt(fromInfo.GetProtoPt());
717             descInfo.Merge(fromInfo);
718             hclassTreeDescInfos_.emplace(descInfo);
719         } else {
720             const_cast<PGOHClassTreeDesc &>(*result).Merge(fromInfo);
721         }
722     }
723 }
724 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header)725 void PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
726 {
727     header_ = header;
728     PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool());
729     if (!abcIdRemap_.empty()) {
730         // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
731         LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
732         profileTypePool_->Remap(*this);
733     }
734     PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_);
735     SectionInfo *info = header->GetRecordInfoSection();
736     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
737     for (uint32_t i = 0; i < info->number_; i++) {
738         ApEntityId recordId(0);
739         ProfileType recordType;
740         if (header->SupportProfileTypeWithAbcId()) {
741             auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
742             recordType = ProfileType(*this, recordTypeRef);
743             recordId = recordType.GetId();
744         } else if (header->SupportRecordPool()) {
745             recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
746         } else {
747             auto *recordName = base::ReadBuffer(&addr);
748             recordPool_->Add(ProfileType(recordId), recordName);
749         }
750         recordType.UpdateId(recordId);
751         recordType.UpdateKind(ProfileType::Kind::RecordClassId);
752         PGOMethodInfoMap *methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
753         if (methodInfos->ParseFromBinary(chunk_.get(), *this, &addr)) {
754             recordInfos_.emplace(recordType, methodInfos);
755         }
756     }
757 
758     info = header->GetLayoutDescSection();
759     if (info == nullptr) {
760         return;
761     }
762     if (header->SupportTrackField()) {
763         ParseFromBinaryForLayout(&addr);
764     }
765 }
766 
ParseFromBinaryForLayout(void ** buffer)767 bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer)
768 {
769     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
770     for (uint32_t i = 0; i < secInfo.number_; i++) {
771         auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
772         if (info == nullptr) {
773             LOG_ECMA(INFO) << "Binary format error!";
774             continue;
775         }
776         hclassTreeDescInfos_.emplace(info->Convert(*this));
777     }
778     return true;
779 }
780 
ProcessToBinary(const SaveTask * task,std::fstream & fileStream,PGOProfilerHeader * const header)781 void PGORecordDetailInfos::ProcessToBinary(
782     const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header)
783 {
784     header_ = header;
785     auto info = header->GetRecordInfoSection();
786     info->number_ = 0;
787     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
788     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
789         if (task && task->IsTerminate()) {
790             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
791             break;
792         }
793         auto recordId = iter->first;
794         auto curMethodInfos = iter->second;
795         if (curMethodInfos->ProcessToBinary(*this, ProfileTypeRef(*this, recordId), task, fileStream, header)) {
796             info->number_++;
797         }
798     }
799     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
800 
801     info = header->GetLayoutDescSection();
802     if (info == nullptr) {
803         return;
804     }
805     info->number_ = 0;
806     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
807     if (header->SupportType()) {
808         if (!ProcessToBinaryForLayout(const_cast<NativeAreaAllocator *>(&nativeAreaAllocator_), task, fileStream)) {
809             return;
810         }
811         info->number_++;
812     }
813     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
814 
815     PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *recordPool_);
816     PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *profileTypePool_->GetPool());
817 }
818 
ProcessToBinaryForLayout(NativeAreaAllocator * allocator,const SaveTask * task,std::fstream & stream)819 bool PGORecordDetailInfos::ProcessToBinaryForLayout(
820     NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream)
821 {
822     SectionInfo secInfo;
823     auto layoutBeginPosition = stream.tellp();
824     stream.seekp(sizeof(SectionInfo), std::ofstream::cur);
825     for (const auto &typeInfo : hclassTreeDescInfos_) {
826         if (task && task->IsTerminate()) {
827             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
828             return false;
829         }
830         auto profileType = PGOSampleType(typeInfo.GetProfileType());
831         size_t size = PGOHClassTreeDescInnerRef::CaculateSize(typeInfo);
832         if (size == 0) {
833             continue;
834         }
835 
836         PGOSampleTypeRef classRef = PGOSampleTypeRef::ConvertFrom(*this, profileType);
837         auto protoSt = PGOSampleType(typeInfo.GetProtoPt());
838         PGOSampleTypeRef protoClassRef = PGOSampleTypeRef::ConvertFrom(*this, protoSt);
839         void *addr = allocator->Allocate(size);
840         auto descInfos = new (addr) PGOHClassTreeDescInnerRef(size, classRef, protoClassRef);
841         descInfos->Merge(typeInfo);
842         stream.write(reinterpret_cast<char *>(descInfos), size);
843         allocator->Delete(addr);
844         secInfo.number_++;
845     }
846 
847     secInfo.offset_ = sizeof(SectionInfo);
848     secInfo.size_ = static_cast<uint32_t>(stream.tellp()) -
849         static_cast<uint32_t>(layoutBeginPosition) - sizeof(SectionInfo);
850     stream.seekp(layoutBeginPosition, std::ofstream::beg)
851         .write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo))
852         .seekp(0, std::ofstream::end);
853     return true;
854 }
855 
ParseFromText(std::ifstream & stream)856 bool PGORecordDetailInfos::ParseFromText(std::ifstream &stream)
857 {
858     std::string details;
859     while (std::getline(stream, details)) {
860         if (details.empty()) {
861             continue;
862         }
863         size_t blockIndex = details.find(DumpUtils::BLOCK_AND_ARRAY_START);
864         if (blockIndex == std::string::npos) {
865             return false;
866         }
867         CString recordName = ConvertToString(details.substr(0, blockIndex));
868 
869         size_t start = details.find_first_of(DumpUtils::ARRAY_START);
870         size_t end = details.find_last_of(DumpUtils::ARRAY_END);
871         if (start == std::string::npos || end == std::string::npos || start > end) {
872             return false;
873         }
874         auto content = details.substr(start + 1, end - (start + 1) - 1);
875         std::vector<std::string> infoStrings = StringHelper::SplitString(content, DumpUtils::BLOCK_SEPARATOR);
876         if (infoStrings.size() <= 0) {
877             continue;
878         }
879 
880         ApEntityId recordId(0);
881         ProfileType profileType(0, recordId, ProfileType::Kind::RecordClassId);
882         auto methodInfosIter = recordInfos_.find(profileType);
883         PGOMethodInfoMap *methodInfos = nullptr;
884         if (methodInfosIter == recordInfos_.end()) {
885             methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
886             recordInfos_.emplace(profileType, methodInfos);
887         } else {
888             methodInfos = methodInfosIter->second;
889         }
890         if (!methodInfos->ParseFromText(chunk_.get(), hotnessThreshold_, infoStrings)) {
891             return false;
892         }
893     }
894     return true;
895 }
896 
ProcessToText(std::ofstream & stream) const897 void PGORecordDetailInfos::ProcessToText(std::ofstream &stream) const
898 {
899     std::string profilerString;
900     bool isFirst = true;
901     for (auto layoutInfoIter : hclassTreeDescInfos_) {
902         if (isFirst) {
903             profilerString += DumpUtils::NEW_LINE;
904             profilerString += DumpUtils::ARRAY_START + DumpUtils::SPACE;
905             isFirst = false;
906         } else {
907             profilerString += DumpUtils::BLOCK_SEPARATOR + DumpUtils::SPACE;
908         }
909         profilerString += PGOHClassTreeDescInner::GetTypeString(layoutInfoIter);
910     }
911     if (!isFirst) {
912         profilerString += (DumpUtils::SPACE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
913         stream << profilerString;
914     }
915     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
916         const CString recordName(recordPool_->GetName(iter->first));
917         ASSERT(!recordName.empty());
918         auto methodInfos = iter->second;
919         methodInfos->ProcessToText(hotnessThreshold_, recordName, stream);
920     }
921     recordPool_->ProcessToText(stream);
922     profileTypePool_->GetPool()->ProcessToText(stream);
923 }
924 
InitSections()925 void PGORecordDetailInfos::InitSections()
926 {
927     recordPool_ = std::make_unique<PGORecordPool>();
928     profileTypePool_ = std::make_unique<PGOProfileTypePool>();
929 }
930 
Clear()931 void PGORecordDetailInfos::Clear()
932 {
933     for (auto iter : recordInfos_) {
934         iter.second->Clear();
935         nativeAreaAllocator_.Delete(iter.second);
936     }
937     for (auto iter : hclassTreeDescInfos_) {
938         iter.Clear();
939     }
940     hclassTreeDescInfos_.clear();
941     recordInfos_.clear();
942     recordPool_->Clear();
943     profileTypePool_->Clear();
944     hclassTreeDescInfos_.clear();
945     abcIdRemap_.clear();
946     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
947     InitSections();
948 }
949 
Match(const CString & abcNormalizedDesc,const CString & recordName,EntityId methodId)950 bool PGORecordSimpleInfos::Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId)
951 {
952     auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
953     if (abcMethodIds == methodIds_.end()) {
954         LOG_COMPILER(DEBUG) << "AbcDesc not found. abcNormalizedDesc: " << abcNormalizedDesc
955                             << ", methodIdsCount: " << methodIds_.size();
956         return false;
957     }
958     auto methodIdsIter = abcMethodIds->second.find(recordName);
959     if (methodIdsIter == abcMethodIds->second.end()) {
960         LOG_COMPILER(DEBUG) << "AbcDesc not found. recordName: " << recordName;
961         return false;
962     }
963     return methodIdsIter->second->Match(methodId);
964 }
965 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header,std::shared_ptr<PGOAbcFilePool> & abcFilePool)966 void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header,
967                                            std::shared_ptr<PGOAbcFilePool> &abcFilePool)
968 {
969     header_ = header;
970     if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool())) {
971         LOG_ECMA(ERROR) << "Parse from binary failed for profile type pool.";
972         return;
973     }
974     if (!abcIdRemap_.empty()) {
975         // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
976         LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
977         profileTypePool_->Remap(*this);
978     }
979     if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_)) {
980         LOG_ECMA(ERROR) << "Parse from binary failed for record pool.";
981         return;
982     }
983     SectionInfo *info = header->GetRecordInfoSection();
984     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
985     for (uint32_t i = 0; i < info->number_; i++) {
986         CString recordName;
987         const char *abcDesc = "";
988         ProfileType recordType;
989         if (header->SupportProfileTypeWithAbcId()) {
990             auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
991             recordType = ProfileType(*this, recordTypeRef);
992             recordName = recordPool_->GetName(recordType);
993             auto abcId = recordType.GetAbcId();
994             const auto *entry = abcFilePool->GetPool()->GetEntry(abcId);
995             if (entry != nullptr) {
996                 abcDesc = entry->GetData().c_str();
997             }
998         } else if (header->SupportRecordPool()) {
999             auto recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
1000             recordName = recordPool_->GetName(ProfileType(recordId));
1001         } else {
1002             recordName = base::ReadBuffer(&addr);
1003         }
1004         PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1005         if (methodIds->ParseFromBinary(*this, &addr)) {
1006             auto methodIdsResult = methodIds_.try_emplace(JSPandaFile::GetNormalizedFileDesc(abcDesc));
1007             (methodIdsResult.first->second).emplace(recordName, methodIds);
1008         }
1009     }
1010 
1011     info = header->GetLayoutDescSection();
1012     if (info == nullptr) {
1013         return;
1014     }
1015     if (header->SupportTrackField()) {
1016         ParseFromBinaryForLayout(&addr);
1017     }
1018 }
1019 
Merge(const PGORecordSimpleInfos & simpleInfos)1020 void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
1021 {
1022     for (const auto &fromAbcMethodIds : simpleInfos.methodIds_) {
1023         auto toAbcMethodIds = methodIds_.try_emplace(fromAbcMethodIds.first);
1024         for (const auto &method : fromAbcMethodIds.second) {
1025             auto result = toAbcMethodIds.first->second.find(method.first);
1026             if (result == toAbcMethodIds.first->second.end()) {
1027                 PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1028                 auto ret = toAbcMethodIds.first->second.emplace(method.first, methodIds);
1029                 ASSERT(ret.second);
1030                 result = ret.first;
1031             }
1032             const_cast<PGOMethodIdSet &>(*result->second).Merge(*method.second);
1033         }
1034     }
1035     recordPool_->Merge(*simpleInfos.recordPool_);
1036     // Merge global layout desc infos to global method info map
1037     for (const auto &hclassTreeDescInfo : simpleInfos.hclassTreeDescInfos_) {
1038         auto result = hclassTreeDescInfos_.find(hclassTreeDescInfo);
1039         if (result == hclassTreeDescInfos_.end()) {
1040             PGOHClassTreeDesc descInfo(hclassTreeDescInfo.GetProfileType());
1041             descInfo.SetProtoPt(hclassTreeDescInfo.GetProtoPt());
1042             descInfo.Merge(hclassTreeDescInfo);
1043             hclassTreeDescInfos_.emplace(descInfo);
1044         } else {
1045             const_cast<PGOHClassTreeDesc &>(*result).Merge(hclassTreeDescInfo);
1046         }
1047     }
1048 }
1049 
ParseFromBinaryForLayout(void ** buffer)1050 bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
1051 {
1052     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
1053     for (uint32_t i = 0; i < secInfo.number_; i++) {
1054         auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
1055         if (info == nullptr) {
1056             LOG_ECMA(INFO) << "Binary format error!";
1057             continue;
1058         }
1059         hclassTreeDescInfos_.emplace(info->Convert(*this));
1060     }
1061     return true;
1062 }
1063 
InitSections()1064 void PGORecordSimpleInfos::InitSections()
1065 {
1066     recordPool_ = std::make_unique<PGORecordPool>();
1067     profileTypePool_ = std::make_unique<PGOProfileTypePool>();
1068 }
1069 
Clear()1070 void PGORecordSimpleInfos::Clear()
1071 {
1072     for (const auto &abcMethodIds: methodIds_) {
1073         for (const auto &iter : abcMethodIds.second) {
1074             iter.second->Clear();
1075             nativeAreaAllocator_.Delete(iter.second);
1076         }
1077     }
1078     for (auto iter : hclassTreeDescInfos_) {
1079         iter.Clear();
1080     }
1081     hclassTreeDescInfos_.clear();
1082     methodIds_.clear();
1083     recordPool_->Clear();
1084     profileTypePool_->Clear();
1085     hclassTreeDescInfos_.clear();
1086     abcIdRemap_.clear();
1087     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1088     InitSections();
1089 }
1090 
PGORecordSimpleInfos(uint32_t threshold)1091 PGORecordSimpleInfos::PGORecordSimpleInfos(uint32_t threshold) : hotnessThreshold_(threshold)
1092 {
1093     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1094     InitSections();
1095 }
1096 
~PGORecordSimpleInfos()1097 PGORecordSimpleInfos::~PGORecordSimpleInfos()
1098 {
1099     Clear();
1100 }
1101 } // namespace panda::ecmascript::pgo
1102