• 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     CMap<ProfileType, PGOMethodInfoMap *> methodInfos = recordInfos.recordInfos_;
702     for (auto iter = methodInfos.begin(); iter != methodInfos.end(); iter++) {
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     std::set<PGOHClassTreeDesc> hclassTreeDescInfos = recordInfos.hclassTreeDescInfos_;
723     for (auto info = hclassTreeDescInfos.begin(); info != hclassTreeDescInfos.end();
724          info++) {
725         auto &fromInfo = *info;
726         auto result = hclassTreeDescInfos_.find(fromInfo);
727         if (result == hclassTreeDescInfos_.end()) {
728             PGOHClassTreeDesc descInfo(fromInfo.GetProfileType());
729             descInfo.SetProtoPt(fromInfo.GetProtoPt());
730             descInfo.Merge(fromInfo);
731             hclassTreeDescInfos_.emplace(descInfo);
732         } else {
733             const_cast<PGOHClassTreeDesc &>(*result).Merge(fromInfo);
734         }
735     }
736 }
737 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header)738 bool PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
739 {
740     header_ = header;
741     // ProfileTypePool must be parsed at first
742     PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool());
743     if (!abcIdRemap_.empty()) {
744         // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
745         LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
746         profileTypePool_->Remap(*this);
747     }
748     PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *protoTransitionPool_);
749     PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_);
750     SectionInfo *info = header->GetRecordInfoSection();
751     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
752     for (uint32_t i = 0; i < info->number_; i++) {
753         ApEntityId recordId(0);
754         ProfileType recordType;
755         if (header->SupportProfileTypeWithAbcId()) {
756             auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
757             bool isValid = true;
758             recordType = ProfileType(*this, recordTypeRef, &isValid);
759             if (!isValid) {
760                 LOG_ECMA(ERROR) << "ParseFromBinary failed, current addr: " << addr << std::endl;
761                 return false;
762             }
763             recordId = recordType.GetId();
764         } else if (header->SupportRecordPool()) {
765             recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
766         } else {
767             auto *recordName = base::ReadBuffer(&addr);
768             recordPool_->Add(ProfileType(recordId), recordName);
769         }
770         recordType.UpdateId(recordId);
771         recordType.UpdateKind(ProfileType::Kind::RecordClassId);
772         PGOMethodInfoMap *methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
773         ASSERT(methodInfos != nullptr);
774         if (methodInfos->ParseFromBinary(chunk_.get(), *this, &addr)) {
775             recordInfos_.emplace(recordType, methodInfos);
776         } else {
777             nativeAreaAllocator_.Delete(methodInfos);
778         }
779     }
780 
781     info = header->GetLayoutDescSection();
782     if (info == nullptr) {
783         return false;
784     }
785     if (header->SupportTrackField()) {
786         ParseFromBinaryForLayout(&addr);
787     }
788     return true;
789 }
790 
ParseFromBinaryForLayout(void ** buffer)791 bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer)
792 {
793     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
794     for (uint32_t i = 0; i < secInfo.number_; i++) {
795         auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
796         if (info == nullptr) {
797             LOG_ECMA(INFO) << "Binary format error!";
798             continue;
799         }
800         hclassTreeDescInfos_.emplace(info->Convert(*this));
801     }
802     return true;
803 }
804 
ProcessToBinary(const SaveTask * task,std::fstream & fileStream,PGOProfilerHeader * const header)805 void PGORecordDetailInfos::ProcessToBinary(
806     const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header)
807 {
808     header_ = header;
809     auto info = header->GetRecordInfoSection();
810     info->number_ = 0;
811     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
812     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
813         if (task && task->IsTerminate()) {
814             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
815             break;
816         }
817         auto recordId = iter->first;
818         auto curMethodInfos = iter->second;
819         if (curMethodInfos->ProcessToBinary(*this, ProfileTypeRef(*this, recordId), task, fileStream, header)) {
820             info->number_++;
821         }
822     }
823     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
824 
825     info = header->GetLayoutDescSection();
826     if (info == nullptr) {
827         return;
828     }
829     info->number_ = 0;
830     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
831     if (header->SupportType()) {
832         if (!ProcessToBinaryForLayout(const_cast<NativeAreaAllocator *>(&nativeAreaAllocator_), task, fileStream)) {
833             return;
834         }
835         info->number_++;
836     }
837     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
838 
839     PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *recordPool_);
840     PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *protoTransitionPool_);
841     // ProfileTypePool must be processed at last
842     PGOFileSectionInterface::ProcessSectionToBinary(*this, fileStream, header, *profileTypePool_->GetPool());
843 }
844 
ProcessToBinaryForLayout(NativeAreaAllocator * allocator,const SaveTask * task,std::fstream & stream)845 bool PGORecordDetailInfos::ProcessToBinaryForLayout(
846     NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream)
847 {
848     SectionInfo secInfo;
849     auto layoutBeginPosition = stream.tellp();
850     stream.seekp(sizeof(SectionInfo), std::ofstream::cur);
851     for (const auto &typeInfo : hclassTreeDescInfos_) {
852         if (task && task->IsTerminate()) {
853             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
854             return false;
855         }
856         auto profileType = PGOSampleType(typeInfo.GetProfileType());
857         size_t size = PGOHClassTreeDescInnerRef::CaculateSize(typeInfo);
858         if (size == 0) {
859             continue;
860         }
861 
862         PGOSampleTypeRef classRef = PGOSampleTypeRef::ConvertFrom(*this, profileType);
863         auto protoSt = PGOSampleType(typeInfo.GetProtoPt());
864         PGOSampleTypeRef protoClassRef = PGOSampleTypeRef::ConvertFrom(*this, protoSt);
865         void *addr = allocator->Allocate(size);
866         auto descInfos = new (addr) PGOHClassTreeDescInnerRef(size, classRef, protoClassRef);
867         descInfos->Merge(typeInfo);
868         stream.write(reinterpret_cast<char *>(descInfos), size);
869         allocator->Delete(addr);
870         secInfo.number_++;
871     }
872 
873     secInfo.offset_ = sizeof(SectionInfo);
874     secInfo.size_ = static_cast<uint32_t>(stream.tellp()) -
875         static_cast<uint32_t>(layoutBeginPosition) - sizeof(SectionInfo);
876     stream.seekp(layoutBeginPosition, std::ofstream::beg)
877         .write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo))
878         .seekp(0, std::ofstream::end);
879     return true;
880 }
881 
ParseFromText(std::ifstream & stream)882 bool PGORecordDetailInfos::ParseFromText(std::ifstream &stream)
883 {
884     std::string details;
885     while (std::getline(stream, details)) {
886         if (details.empty()) {
887             continue;
888         }
889         size_t blockIndex = details.find(DumpUtils::BLOCK_AND_ARRAY_START);
890         if (blockIndex == std::string::npos) {
891             return false;
892         }
893         CString recordName = ConvertToString(details.substr(0, blockIndex));
894 
895         size_t start = details.find_first_of(DumpUtils::ARRAY_START);
896         size_t end = details.find_last_of(DumpUtils::ARRAY_END);
897         if (start == std::string::npos || end == std::string::npos || start > end) {
898             return false;
899         }
900         ASSERT(end > start + 1);
901         auto content = details.substr(start + 1, end - (start + 1) - 1);
902         std::vector<std::string> infoStrings = StringHelper::SplitString(content, DumpUtils::BLOCK_SEPARATOR);
903         if (infoStrings.size() <= 0) {
904             continue;
905         }
906 
907         ApEntityId recordId(0);
908         ProfileType profileType(0, recordId, ProfileType::Kind::RecordClassId);
909         auto methodInfosIter = recordInfos_.find(profileType);
910         PGOMethodInfoMap *methodInfos = nullptr;
911         if (methodInfosIter == recordInfos_.end()) {
912             methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
913             recordInfos_.emplace(profileType, methodInfos);
914         } else {
915             methodInfos = methodInfosIter->second;
916         }
917         ASSERT(methodInfos != nullptr);
918         if (!methodInfos->ParseFromText(chunk_.get(), hotnessThreshold_, infoStrings)) {
919             return false;
920         }
921     }
922     return true;
923 }
924 
ProcessToText(std::ofstream & stream) const925 void PGORecordDetailInfos::ProcessToText(std::ofstream &stream) const
926 {
927     std::string profilerString;
928     bool isFirst = true;
929     for (auto layoutInfoIter : hclassTreeDescInfos_) {
930         if (isFirst) {
931             profilerString += DumpUtils::NEW_LINE;
932             profilerString += DumpUtils::ARRAY_START + DumpUtils::SPACE;
933             isFirst = false;
934         } else {
935             profilerString += DumpUtils::BLOCK_SEPARATOR + DumpUtils::SPACE;
936         }
937         profilerString += PGOHClassTreeDescInner::GetTypeString(layoutInfoIter);
938     }
939     if (!isFirst) {
940         profilerString += (DumpUtils::SPACE + DumpUtils::ARRAY_END + DumpUtils::NEW_LINE);
941         stream << profilerString;
942     }
943     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
944         const CString recordName(recordPool_->GetName(iter->first));
945         ASSERT(!recordName.empty());
946         auto methodInfos = iter->second;
947         methodInfos->ProcessToText(hotnessThreshold_, recordName, stream);
948     }
949     recordPool_->ProcessToText(stream);
950     protoTransitionPool_->ProcessToText(stream);
951     // ProfileTypePool must be processed at last
952     profileTypePool_->GetPool()->ProcessToText(stream);
953 }
954 
InitSections()955 void PGORecordDetailInfos::InitSections()
956 {
957     recordPool_ = std::make_unique<PGORecordPool>();
958     protoTransitionPool_ = std::make_unique<PGOProtoTransitionPool>();
959     profileTypePool_ = std::make_unique<PGOProfileTypePool>();
960 }
961 
Clear()962 void PGORecordDetailInfos::Clear()
963 {
964     for (auto iter : recordInfos_) {
965         iter.second->Clear();
966         nativeAreaAllocator_.Delete(iter.second);
967     }
968     for (auto iter : hclassTreeDescInfos_) {
969         iter.Clear();
970     }
971     hclassTreeDescInfos_.clear();
972     recordInfos_.clear();
973     recordPool_->Clear();
974     protoTransitionPool_->Clear();
975     profileTypePool_->Clear();
976     hclassTreeDescInfos_.clear();
977     abcIdRemap_.clear();
978     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
979     InitSections();
980 }
981 
Match(const CString & abcNormalizedDesc,const CString & recordName,EntityId methodId)982 bool PGORecordSimpleInfos::Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId)
983 {
984     auto abcMethodIds = methodIds_.find(abcNormalizedDesc);
985     if (abcMethodIds == methodIds_.end()) {
986         LOG_COMPILER(DEBUG) << "AbcDesc not found. abcNormalizedDesc: " << abcNormalizedDesc
987                             << ", methodIdsCount: " << methodIds_.size();
988         return false;
989     }
990     auto methodIdsIter = abcMethodIds->second.find(recordName);
991     if (methodIdsIter == abcMethodIds->second.end()) {
992         LOG_COMPILER(DEBUG) << "AbcDesc not found. recordName: " << recordName;
993         return false;
994     }
995     return methodIdsIter->second->Match(methodId);
996 }
997 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header,std::shared_ptr<PGOAbcFilePool> & abcFilePool)998 void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header,
999                                            std::shared_ptr<PGOAbcFilePool> &abcFilePool)
1000 {
1001     header_ = header;
1002     // ProfileTypePool must be parsed at first
1003     if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *profileTypePool_->GetPool())) {
1004         LOG_ECMA(ERROR) << "Parse from binary failed for profile type pool.";
1005         return;
1006     }
1007     if (!abcIdRemap_.empty()) {
1008         // step2: [abc pool merge] remap decoder's profileType pool's abcId field.
1009         LOG_ECMA(DEBUG) << "remap with abcRemapSize: " << abcIdRemap_.size();
1010         profileTypePool_->Remap(*this);
1011     }
1012     if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *protoTransitionPool_)) {
1013         LOG_ECMA(ERROR) << "Parse from binary failed for proto transition pool.";
1014         return;
1015     }
1016     if (!PGOFileSectionInterface::ParseSectionFromBinary(*this, buffer, header, *recordPool_)) {
1017         LOG_ECMA(ERROR) << "Parse from binary failed for record pool.";
1018         return;
1019     }
1020     SectionInfo *info = header->GetRecordInfoSection();
1021     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
1022     for (uint32_t i = 0; i < info->number_; i++) {
1023         CString recordName;
1024         const char *abcDesc = "";
1025         ProfileType recordType;
1026         if (header->SupportProfileTypeWithAbcId()) {
1027             auto recordTypeRef = ProfileTypeRef(base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId)));
1028             recordType = ProfileType(*this, recordTypeRef);
1029             recordName = recordPool_->GetName(recordType);
1030             auto abcId = recordType.GetAbcId();
1031             const auto *entry = abcFilePool->GetPool()->GetEntry(abcId);
1032             if (entry != nullptr) {
1033                 abcDesc = entry->GetData().c_str();
1034             }
1035         } else if (header->SupportRecordPool()) {
1036             auto recordId = base::ReadBuffer<ApEntityId>(&addr, sizeof(ApEntityId));
1037             recordName = recordPool_->GetName(ProfileType(recordId));
1038         } else {
1039             recordName = base::ReadBuffer(&addr);
1040         }
1041         PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1042         if (methodIds->ParseFromBinary(*this, &addr)) {
1043             auto methodIdsResult = methodIds_.try_emplace(JSPandaFile::GetNormalizedFileDesc(abcDesc));
1044             // check record name, the default record name of the framework abc does not enter the aot compilation
1045             FrameworkHelper::GetRealRecordName(recordName);
1046             (methodIdsResult.first->second).emplace(recordName, methodIds);
1047         } else {
1048             nativeAreaAllocator_.Delete(methodIds);
1049         }
1050     }
1051 
1052     info = header->GetLayoutDescSection();
1053     if (info == nullptr) {
1054         return;
1055     }
1056     if (header->SupportTrackField()) {
1057         ParseFromBinaryForLayout(&addr);
1058     }
1059 }
1060 
Merge(const PGORecordSimpleInfos & simpleInfos)1061 void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
1062 {
1063     for (const auto &fromAbcMethodIds : simpleInfos.methodIds_) {
1064         auto toAbcMethodIds = methodIds_.try_emplace(fromAbcMethodIds.first);
1065         for (const auto &method : fromAbcMethodIds.second) {
1066             auto result = toAbcMethodIds.first->second.find(method.first);
1067             if (result == toAbcMethodIds.first->second.end()) {
1068                 PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1069                 auto ret = toAbcMethodIds.first->second.emplace(method.first, methodIds);
1070                 ASSERT(ret.second);
1071                 result = ret.first;
1072             }
1073             const_cast<PGOMethodIdSet &>(*result->second).Merge(*method.second);
1074         }
1075     }
1076     recordPool_->Merge(*simpleInfos.recordPool_);
1077     protoTransitionPool_->Merge(*simpleInfos.protoTransitionPool_);
1078     // Merge global layout desc infos to global method info map
1079     for (const auto &hclassTreeDescInfo : simpleInfos.hclassTreeDescInfos_) {
1080         auto result = hclassTreeDescInfos_.find(hclassTreeDescInfo);
1081         if (result == hclassTreeDescInfos_.end()) {
1082             PGOHClassTreeDesc descInfo(hclassTreeDescInfo.GetProfileType());
1083             descInfo.SetProtoPt(hclassTreeDescInfo.GetProtoPt());
1084             descInfo.Merge(hclassTreeDescInfo);
1085             hclassTreeDescInfos_.emplace(descInfo);
1086         } else {
1087             const_cast<PGOHClassTreeDesc &>(*result).Merge(hclassTreeDescInfo);
1088         }
1089     }
1090 }
1091 
ParseFromBinaryForLayout(void ** buffer)1092 bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
1093 {
1094     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
1095     for (uint32_t i = 0; i < secInfo.number_; i++) {
1096         auto *info = base::ReadBufferInSize<PGOHClassTreeDescInnerRef>(buffer);
1097         if (info == nullptr) {
1098             LOG_ECMA(INFO) << "Binary format error!";
1099             continue;
1100         }
1101         hclassTreeDescInfos_.emplace(info->Convert(*this));
1102     }
1103     return true;
1104 }
1105 
InitSections()1106 void PGORecordSimpleInfos::InitSections()
1107 {
1108     recordPool_ = std::make_unique<PGORecordPool>();
1109     protoTransitionPool_ = std::make_unique<PGOProtoTransitionPool>();
1110     profileTypePool_ = std::make_unique<PGOProfileTypePool>();
1111 }
1112 
Clear()1113 void PGORecordSimpleInfos::Clear()
1114 {
1115     for (const auto &abcMethodIds: methodIds_) {
1116         for (const auto &iter : abcMethodIds.second) {
1117             iter.second->Clear();
1118             nativeAreaAllocator_.Delete(iter.second);
1119         }
1120     }
1121     for (auto iter : hclassTreeDescInfos_) {
1122         iter.Clear();
1123     }
1124     hclassTreeDescInfos_.clear();
1125     methodIds_.clear();
1126     recordPool_->Clear();
1127     profileTypePool_->Clear();
1128     hclassTreeDescInfos_.clear();
1129     abcIdRemap_.clear();
1130     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1131     InitSections();
1132 }
1133 
PGORecordSimpleInfos(uint32_t threshold)1134 PGORecordSimpleInfos::PGORecordSimpleInfos(uint32_t threshold) : hotnessThreshold_(threshold)
1135 {
1136     chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1137     InitSections();
1138 }
1139 
~PGORecordSimpleInfos()1140 PGORecordSimpleInfos::~PGORecordSimpleInfos()
1141 {
1142     Clear();
1143 }
1144 } // namespace panda::ecmascript::pgo
1145