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