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