• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/pgo_profiler/pgo_profiler_info.h"
17 #include <cstdint>
18 #include <fstream>
19 #include <iomanip>
20 
21 #include "ecmascript/base/bit_helper.h"
22 #include "ecmascript/base/file_header.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/jspandafile/method_literal.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "ecmascript/mem/c_string.h"
27 #include "ecmascript/pgo_profiler/pgo_profiler_encoder.h"
28 #include "macros.h"
29 #include "securec.h"
30 #include "zlib.h"
31 
32 namespace panda::ecmascript {
33 static const std::string ELEMENT_SEPARATOR = "/";
34 static const std::string BLOCK_SEPARATOR = ",";
35 static const std::string TYPE_SEPARATOR = "|";
36 static const std::string BLOCK_START = ":";
37 static const std::string ARRAY_START = "[";
38 static const std::string ARRAY_END = "]";
39 static const std::string NEW_LINE = "\n";
40 static const std::string SPACE = " ";
41 static const std::string BLOCK_AND_ARRAY_START = BLOCK_START + SPACE + ARRAY_START + SPACE;
42 static const std::string VERSION_HEADER = "Profiler Version" + BLOCK_START + SPACE;
43 static const std::string PANDA_FILE_INFO_HEADER = "Panda file sumcheck list" + BLOCK_AND_ARRAY_START;
44 static const uint32_t HEX_FORMAT_WIDTH_FOR_32BITS = 10; // for example, 0xffffffff is 10 characters
45 
BuildFromLegacy(void * buffer,PGOProfilerHeader ** header)46 bool PGOProfilerHeader::BuildFromLegacy(void *buffer, PGOProfilerHeader **header)
47 {
48     auto *inHeader = reinterpret_cast<PGOProfilerHeaderLegacy *>(buffer);
49     size_t desSize = Size(inHeader->GetSectionNumber());
50     if (desSize > LastSize()) {
51         LOG_ECMA(ERROR) << "header size error, expected size is less than " << LastSize() << ", but got " << desSize;
52         return false;
53     }
54     Build(header, desSize);
55     // copy header base.
56     if (memcpy_s(*header, sizeof(FileHeaderBase), inHeader, sizeof(FileHeaderBase)) != EOK) {
57         UNREACHABLE();
58     }
59     // skip elastic header field, and copy section info from incoming buffer.
60     auto sectionSize = desSize - sizeof(FileHeaderElastic);
61     if (memcpy_s(&((*header)->sectionNumber_), sectionSize, &(inHeader->GetSectionNumber()), sectionSize) != EOK) {
62         UNREACHABLE();
63     }
64     return true;
65 }
66 
BuildFromElastic(void * buffer,size_t bufferSize,PGOProfilerHeader ** header)67 bool PGOProfilerHeader::BuildFromElastic(void *buffer, size_t bufferSize, PGOProfilerHeader **header)
68 {
69     auto *inHeader = reinterpret_cast<PGOProfilerHeader *>(buffer);
70     if (!inHeader->Verify(buffer, bufferSize)) {
71         return false;
72     }
73     size_t desSize = inHeader->Size();
74     if (desSize > LastSize()) {
75         LOG_ECMA(ERROR) << "header size error, expected size is less than " << LastSize() << ", but got " << desSize;
76         return false;
77     }
78     Build(header, desSize);
79     if (memcpy_s(*header, desSize, inHeader, desSize) != EOK) {
80         UNREACHABLE();
81     }
82     return true;
83 }
84 
ParseFromBinary(void * buffer,size_t bufferSize,PGOProfilerHeader ** header)85 bool PGOProfilerHeader::ParseFromBinary(void *buffer, size_t bufferSize, PGOProfilerHeader **header)
86 {
87     auto *inHeaderBase = reinterpret_cast<FileHeaderBase *>(buffer);
88     if (inHeaderBase->VerifyVersion("apPath file", LAST_VERSION, false)) {
89         if (!inHeaderBase->CompatibleVerify(ELASTIC_HEADER_MINI_VERSION)) {
90             return BuildFromLegacy(buffer, header);
91         }
92         return BuildFromElastic(buffer, bufferSize, header);
93     }
94     return false;
95 }
96 
VerifyFileSize(size_t bufferSize) const97 bool PGOProfilerHeader::VerifyFileSize(size_t bufferSize) const
98 {
99     if (!SupportFileSize()) {
100         return true;
101     }
102     if (GetFileSize() != bufferSize) {
103         LOG_ECMA(ERROR) << "Verify ap file's file size failed. size: " << std::hex << bufferSize << " vs "
104                         << GetFileSize();
105         return false;
106     }
107     return true;
108 }
109 
VerifyConsistency(void * buffer,size_t bufferSize) const110 bool PGOProfilerHeader::VerifyConsistency(void *buffer, size_t bufferSize) const
111 {
112     if (!SupportFileConsistency()) {
113         return true;
114     }
115     uint32_t checksum = adler32(0, reinterpret_cast<const Bytef *>(buffer) + MAGIC_SIZE, VERSION_SIZE);
116     checksum = adler32(checksum, reinterpret_cast<const Bytef *>(buffer) + CHECKSUM_END_OFFSET,
117                        bufferSize - CHECKSUM_END_OFFSET);
118     if (checksum != GetChecksum()) {
119         LOG_ECMA(ERROR) << "Verify ap file's consistency failed. checksum: " << std::hex << checksum << " vs "
120                         << std::hex << GetChecksum();
121         return false;
122     }
123     return true;
124 }
125 
ProcessToBinary(std::fstream & fileStream) const126 void PGOProfilerHeader::ProcessToBinary(std::fstream &fileStream) const
127 {
128     fileStream.seekp(0);
129     if (base::FileHeaderBase::CompatibleVerify(ELASTIC_HEADER_MINI_VERSION)) {
130         fileStream.write(reinterpret_cast<const char *>(this), Size());
131     } else {
132         // copy header base.
133         fileStream.write(reinterpret_cast<const char *>(this), sizeof(FileHeaderBase));
134         // skip elastic header field, and copy section info from incoming buffer.
135         auto sectionSize = Size() - sizeof(FileHeaderElastic);
136         fileStream.write(reinterpret_cast<const char *>(&sectionNumber_), sectionSize);
137     }
138 }
139 
ParseFromText(std::ifstream & stream)140 bool PGOProfilerHeader::ParseFromText(std::ifstream &stream)
141 {
142     std::string header;
143     if (std::getline(stream, header)) {
144         if (header.empty()) {
145             return false;
146         }
147         auto index = header.find(BLOCK_START);
148         if (index == std::string::npos) {
149             return false;
150         }
151         auto version = header.substr(index + 1);
152         if (!InternalSetVersion(version)) {
153             return false;
154         }
155         if (!Verify()) {
156             return false;
157         }
158         if (!base::FileHeaderBase::CompatibleVerify(ELASTIC_HEADER_MINI_VERSION)) {
159             auto *pandaInfoSection = GetPandaInfoSection();
160             pandaInfoSection->offset_ -= sizeof(PGOProfilerHeader) - sizeof(PGOProfilerHeaderLegacy);
161         }
162         return true;
163     }
164     return false;
165 }
166 
ProcessToText(std::ofstream & stream) const167 bool PGOProfilerHeader::ProcessToText(std::ofstream &stream) const
168 {
169     if (!Verify()) {
170         return false;
171     }
172     stream << VERSION_HEADER << InternalGetVersion() << NEW_LINE;
173     if (SupportFileConsistency()) {
174         stream << "FileSize: " << GetFileSize() << " ,HeaderSize: " << GetHeaderSize() << " ,Checksum: " << std::hex
175                << GetChecksum() << NEW_LINE;
176     }
177     return true;
178 }
179 
ParseFromBinary(void * buffer,SectionInfo * const info)180 void PGOPandaFileInfos::ParseFromBinary(void *buffer, SectionInfo *const info)
181 {
182     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
183     for (uint32_t i = 0; i < info->number_; i++) {
184         fileInfos_.emplace(*base::ReadBufferInSize<FileInfo>(&addr));
185     }
186     LOG_ECMA(DEBUG) << "Profiler panda file count:" << info->number_;
187 }
188 
ProcessToBinary(std::fstream & fileStream,SectionInfo * info) const189 void PGOPandaFileInfos::ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const
190 {
191     fileStream.seekp(info->offset_);
192     info->number_ = fileInfos_.size();
193     for (auto localInfo : fileInfos_) {
194         fileStream.write(reinterpret_cast<char *>(&localInfo), localInfo.Size());
195     }
196     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
197 }
198 
Merge(const PGOPandaFileInfos & pandaFileInfos)199 void PGOPandaFileInfos::Merge(const PGOPandaFileInfos &pandaFileInfos)
200 {
201     for (const auto &info : pandaFileInfos.fileInfos_) {
202         fileInfos_.emplace(info.GetChecksum());
203     }
204 }
205 
VerifyChecksum(const PGOPandaFileInfos & pandaFileInfos,const std::string & base,const std::string & incoming) const206 bool PGOPandaFileInfos::VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
207                                        const std::string &incoming) const
208 {
209     std::set<FileInfo> unionChecksum;
210     set_union(fileInfos_.begin(), fileInfos_.end(), pandaFileInfos.fileInfos_.begin(), pandaFileInfos.fileInfos_.end(),
211               inserter(unionChecksum, unionChecksum.begin()));
212     if (!fileInfos_.empty() && unionChecksum.empty()) {
213         LOG_ECMA(ERROR) << "First AP file(" << base << ") and the incoming file(" << incoming
214                         << ") do not come from the same abc file, skip merge the incoming file.";
215         return false;
216     }
217     return true;
218 }
219 
ParseFromText(std::ifstream & stream)220 bool PGOPandaFileInfos::ParseFromText(std::ifstream &stream)
221 {
222     std::string pandaFileInfo;
223     while (std::getline(stream, pandaFileInfo)) {
224         if (pandaFileInfo.empty()) {
225             continue;
226         }
227 
228         size_t start = pandaFileInfo.find_first_of(ARRAY_START);
229         size_t end = pandaFileInfo.find_last_of(ARRAY_END);
230         if (start == std::string::npos || end == std::string::npos || start > end) {
231             return false;
232         }
233         auto content = pandaFileInfo.substr(start + 1, end - (start + 1) - 1);
234         std::vector<std::string> infos = base::StringHelper::SplitString(content, BLOCK_SEPARATOR);
235         for (auto checksum : infos) {
236             uint32_t result;
237             if (!base::StringHelper::StrToUInt32(checksum.c_str(), &result)) {
238                 LOG_ECMA(ERROR) << "checksum: " << checksum << " parse failed";
239                 return false;
240             }
241             Sample(result);
242         }
243         return true;
244     }
245     return true;
246 }
247 
ProcessToText(std::ofstream & stream) const248 void PGOPandaFileInfos::ProcessToText(std::ofstream &stream) const
249 {
250     std::string pandaFileInfo = NEW_LINE + PANDA_FILE_INFO_HEADER;
251     bool isFirst = true;
252     for (auto &info : fileInfos_) {
253         if (!isFirst) {
254             pandaFileInfo += BLOCK_SEPARATOR + SPACE;
255         } else {
256             isFirst = false;
257         }
258         pandaFileInfo += std::to_string(info.GetChecksum());
259     }
260 
261     pandaFileInfo += (SPACE + ARRAY_END + NEW_LINE);
262     stream << pandaFileInfo;
263 }
264 
Checksum(uint32_t checksum) const265 bool PGOPandaFileInfos::Checksum(uint32_t checksum) const
266 {
267     if (fileInfos_.find(checksum) == fileInfos_.end()) {
268         LOG_ECMA(ERROR) << "Checksum verification failed. Please ensure that the .abc and .ap match.";
269         return false;
270     }
271     return true;
272 }
273 
ProcessToText(std::string & text) const274 void PGOMethodInfo::ProcessToText(std::string &text) const
275 {
276     text += std::to_string(GetMethodId().GetOffset());
277     text += ELEMENT_SEPARATOR;
278     text += std::to_string(GetCount());
279     text += ELEMENT_SEPARATOR;
280     text += GetSampleModeToString();
281     text += ELEMENT_SEPARATOR;
282     text += GetMethodName();
283 }
284 
ParseFromText(const std::string & infoString)285 std::vector<std::string> PGOMethodInfo::ParseFromText(const std::string &infoString)
286 {
287     std::vector<std::string> infoStrings = base::StringHelper::SplitString(infoString, ELEMENT_SEPARATOR);
288     return infoStrings;
289 }
290 
CalcChecksum(const char * name,const uint8_t * byteCodeArray,uint32_t byteCodeLength)291 uint32_t PGOMethodInfo::CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength)
292 {
293     uint32_t checksum = 0;
294     if (byteCodeArray != nullptr) {
295         checksum = CalcOpCodeChecksum(byteCodeArray, byteCodeLength);
296     }
297 
298     if (name != nullptr) {
299         checksum = adler32(checksum, reinterpret_cast<const Bytef *>(name), strlen(name));
300     }
301     return checksum;
302 }
303 
CalcOpCodeChecksum(const uint8_t * byteCodeArray,uint32_t byteCodeLength)304 uint32_t PGOMethodInfo::CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength)
305 {
306     uint32_t checksum = 0;
307     BytecodeInstruction bcIns(byteCodeArray);
308     auto bcInsLast = bcIns.JumpTo(byteCodeLength);
309     while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
310         auto opCode = bcIns.GetOpcode();
311         checksum = adler32(checksum, reinterpret_cast<const Bytef *>(&opCode), sizeof(decltype(opCode)));
312         bcIns = bcIns.GetNext();
313     }
314     return checksum;
315 }
316 
Merge(const PGOMethodTypeSet * info)317 void PGOMethodTypeSet::Merge(const PGOMethodTypeSet *info)
318 {
319     for (const auto &fromType : info->scalarOpTypeInfos_) {
320         auto iter = scalarOpTypeInfos_.find(fromType);
321         if (iter != scalarOpTypeInfos_.end()) {
322             const_cast<ScalarOpTypeInfo &>(*iter).Merge(fromType);
323         } else {
324             scalarOpTypeInfos_.emplace(fromType);
325         }
326     }
327     for (const auto &fromType : info->rwScalarOpTypeInfos_) {
328         auto iter = rwScalarOpTypeInfos_.find(fromType);
329         if (iter != rwScalarOpTypeInfos_.end()) {
330             const_cast<RWScalarOpTypeInfo &>(*iter).Merge(fromType);
331         } else {
332             rwScalarOpTypeInfos_.emplace(fromType);
333         }
334     }
335     for (const auto &fromType : info->objDefOpTypeInfos_) {
336         AddDefine(fromType.GetOffset(), fromType.GetType(), fromType.GetSuperType());
337     }
338 }
339 
SkipFromBinary(void ** buffer)340 void PGOMethodTypeSet::SkipFromBinary(void **buffer)
341 {
342     uint32_t size = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
343     for (uint32_t i = 0; i < size; i++) {
344         base::ReadBufferInSize<ScalarOpTypeInfo>(buffer);
345     }
346 }
347 
ParseFromBinary(void ** buffer,PGOProfilerHeader * const header)348 bool PGOMethodTypeSet::ParseFromBinary(void **buffer, PGOProfilerHeader *const header)
349 {
350     uint32_t size = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
351     for (uint32_t i = 0; i < size; i++) {
352         auto typeInfo = base::ReadBufferInSize<TypeInfoHeader>(buffer);
353         if (typeInfo->GetInfoType() == InfoType::OP_TYPE) {
354             scalarOpTypeInfos_.emplace(*reinterpret_cast<ScalarOpTypeInfo *>(typeInfo));
355         } else if (typeInfo->GetInfoType() == InfoType::DEFINE_CLASS_TYPE) {
356             objDefOpTypeInfos_.emplace(*reinterpret_cast<ObjDefOpTypeInfo *>(typeInfo));
357         } else if (header->SupportUseHClassType() && typeInfo->GetInfoType() == InfoType::USE_HCLASS_TYPE) {
358             rwScalarOpTypeInfos_.emplace(*reinterpret_cast<RWScalarOpTypeInfo *>(typeInfo));
359         }
360     }
361     return true;
362 }
363 
ProcessToBinary(std::stringstream & stream) const364 bool PGOMethodTypeSet::ProcessToBinary(std::stringstream &stream) const
365 {
366     uint32_t number = 0;
367     std::stringstream methodStream;
368     for (auto typeInfo : scalarOpTypeInfos_) {
369         if (!typeInfo.GetType().IsNone()) {
370             methodStream.write(reinterpret_cast<char *>(&typeInfo), typeInfo.Size());
371             number++;
372         }
373     }
374     for (auto typeInfo : rwScalarOpTypeInfos_) {
375         if (typeInfo.GetCount() != 0) {
376             methodStream.write(reinterpret_cast<char *>(&typeInfo), typeInfo.Size());
377             number++;
378         }
379     }
380 
381     for (auto typeInfo : objDefOpTypeInfos_) {
382         methodStream.write(reinterpret_cast<char *>(&typeInfo), typeInfo.Size());
383         number++;
384     }
385 
386     stream.write(reinterpret_cast<char *>(&number), sizeof(uint32_t));
387     if (number > 0) {
388         stream << methodStream.rdbuf();
389         return true;
390     }
391     return false;
392 }
393 
ParseFromText(const std::string & typeString)394 bool PGOMethodTypeSet::ParseFromText(const std::string &typeString)
395 {
396     std::vector<std::string> typeInfoVector = base::StringHelper::SplitString(typeString, TYPE_SEPARATOR);
397     if (typeInfoVector.size() > 0) {
398         for (const auto &iter : typeInfoVector) {
399             std::vector<std::string> typeStrings = base::StringHelper::SplitString(iter, BLOCK_START);
400             if (typeStrings.size() < METHOD_TYPE_INFO_COUNT) {
401                 return false;
402             }
403 
404             uint32_t offset;
405             if (!base::StringHelper::StrToUInt32(typeStrings[METHOD_OFFSET_INDEX].c_str(), &offset)) {
406                 return false;
407             }
408             uint32_t type;
409             if (!base::StringHelper::StrToUInt32(typeStrings[METHOD_TYPE_INDEX].c_str(), &type)) {
410                 return false;
411             }
412             scalarOpTypeInfos_.emplace(offset, PGOSampleType(type));
413         }
414     }
415     return true;
416 }
417 
ProcessToText(std::string & text) const418 void PGOMethodTypeSet::ProcessToText(std::string &text) const
419 {
420     bool isFirst = true;
421     for (auto typeInfoIter : scalarOpTypeInfos_) {
422         if (typeInfoIter.GetType().IsNone()) {
423             continue;
424         }
425         if (isFirst) {
426             text += ARRAY_START + SPACE;
427             isFirst = false;
428         } else {
429             text += TYPE_SEPARATOR + SPACE;
430         }
431         text += std::to_string(typeInfoIter.GetOffset());
432         text += BLOCK_START;
433         text += typeInfoIter.GetType().GetTypeString();
434     }
435     for (auto rwScalarOpTypeInfoIter : rwScalarOpTypeInfos_) {
436         if (rwScalarOpTypeInfoIter.GetCount() == 0) {
437             continue;
438         }
439         if (isFirst) {
440             text += ARRAY_START + SPACE;
441             isFirst = false;
442         } else {
443             text += TYPE_SEPARATOR + SPACE;
444         }
445         rwScalarOpTypeInfoIter.ProcessToText(text);
446     }
447     for (const auto &defTypeInfoIter : objDefOpTypeInfos_) {
448         if (isFirst) {
449             text += ARRAY_START + SPACE;
450             isFirst = false;
451         } else {
452             text += TYPE_SEPARATOR + SPACE;
453         }
454         defTypeInfoIter.ProcessToText(text);
455     }
456     if (!isFirst) {
457         text += (SPACE + ARRAY_END);
458     }
459 }
460 
CaculateSize(const PGOHClassLayoutDesc & desc)461 size_t PGOHClassLayoutDescInner::CaculateSize(const PGOHClassLayoutDesc &desc)
462 {
463     if (desc.GetLayoutDesc().empty() && desc.GetPtLayoutDesc().empty() && desc.GetCtorLayoutDesc().empty()) {
464         return sizeof(PGOHClassLayoutDescInner);
465     }
466     size_t size = sizeof(PGOHClassLayoutDescInner) - sizeof(PGOLayoutDescInfo);
467     for (const auto &iter : desc.GetLayoutDesc()) {
468         auto key = iter.first;
469         if (key.size() > 0) {
470             size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size()));
471         }
472     }
473     for (const auto &iter : desc.GetPtLayoutDesc()) {
474         auto key = iter.first;
475         if (key.size() > 0) {
476             size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size()));
477         }
478     }
479     for (const auto &iter : desc.GetCtorLayoutDesc()) {
480         auto key = iter.first;
481         if (key.size() > 0) {
482             size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size()));
483         }
484     }
485     size += sizeof(ElementsKind);
486     return size;
487 }
488 
GetTypeString(const PGOHClassLayoutDesc & desc)489 std::string PGOHClassLayoutDescInner::GetTypeString(const PGOHClassLayoutDesc &desc)
490 {
491     std::string text;
492     text += desc.GetClassType().GetTypeString();
493     if (!desc.GetSuperClassType().IsNone()) {
494         text += TYPE_SEPARATOR + SPACE;
495         text += desc.GetSuperClassType().GetTypeString();
496     }
497     if (!Elements::IsNone(desc.GetElementsKind())) {
498         text += TYPE_SEPARATOR + SPACE;
499         text += Elements::GetString(desc.GetElementsKind());
500     }
501     text += BLOCK_AND_ARRAY_START;
502     bool isLayoutFirst = true;
503     for (const auto &layoutDesc : desc.GetLayoutDesc()) {
504         if (!isLayoutFirst) {
505             text += TYPE_SEPARATOR + SPACE;
506         } else {
507             text += ARRAY_START;
508         }
509         isLayoutFirst = false;
510         text += layoutDesc.first;
511         text += BLOCK_START;
512         text += std::to_string(layoutDesc.second.GetValue());
513     }
514     if (!isLayoutFirst) {
515         text += ARRAY_END;
516     }
517     bool isPtLayoutFirst = true;
518     for (const auto &layoutDesc : desc.GetPtLayoutDesc()) {
519         if (!isPtLayoutFirst) {
520             text += TYPE_SEPARATOR + SPACE;
521         } else {
522             if (!isLayoutFirst) {
523                 text += TYPE_SEPARATOR + SPACE;
524             }
525             text += ARRAY_START;
526         }
527         isPtLayoutFirst = false;
528         text += layoutDesc.first;
529         text += BLOCK_START;
530         text += std::to_string(layoutDesc.second.GetValue());
531     }
532     if (!isPtLayoutFirst) {
533         text += ARRAY_END;
534     }
535     bool isCtorLayoutFirst = true;
536     for (const auto &layoutDesc : desc.GetCtorLayoutDesc()) {
537         if (!isCtorLayoutFirst) {
538             text += TYPE_SEPARATOR + SPACE;
539         } else {
540             if (!isLayoutFirst || !isPtLayoutFirst) {
541                 text += TYPE_SEPARATOR + SPACE;
542             }
543             text += ARRAY_START;
544         }
545         isCtorLayoutFirst = false;
546         text += layoutDesc.first;
547         text += BLOCK_START;
548         text += std::to_string(layoutDesc.second.GetValue());
549     }
550     if (!isCtorLayoutFirst) {
551         text += ARRAY_END;
552     }
553     text += (SPACE + ARRAY_END);
554     return text;
555 }
556 
Merge(const PGOHClassLayoutDesc & desc)557 void PGOHClassLayoutDescInner::Merge(const PGOHClassLayoutDesc &desc)
558 {
559     auto current = const_cast<PGOLayoutDescInfo *>(GetFirst());
560     for (const auto &iter : desc.GetLayoutDesc()) {
561         auto key = iter.first;
562         auto type = iter.second;
563         if (key.size() > 0) {
564             new (current) PGOLayoutDescInfo(key, type);
565             current = const_cast<PGOLayoutDescInfo *>(GetNext(current));
566             count_++;
567         }
568     }
569     for (const auto &iter : desc.GetPtLayoutDesc()) {
570         auto key = iter.first;
571         auto type = iter.second;
572         if (key.size() > 0) {
573             new (current) PGOLayoutDescInfo(key, type);
574             current = const_cast<PGOLayoutDescInfo *>(GetNext(current));
575             ptCount_++;
576         }
577     }
578     for (const auto &iter : desc.GetCtorLayoutDesc()) {
579         auto key = iter.first;
580         auto type = iter.second;
581         if (key.size() > 0) {
582             new (current) PGOLayoutDescInfo(key, type);
583             current = const_cast<PGOLayoutDescInfo *>(GetNext(current));
584             ctorCount_++;
585         }
586     }
587 }
588 
ProcessToText(std::string & text) const589 void PGOMethodTypeSet::RWScalarOpTypeInfo::ProcessToText(std::string &text) const
590 {
591     text += std::to_string(GetOffset());
592     text += BLOCK_START;
593     text += ARRAY_START + SPACE;
594     bool isFirst = true;
595     for (uint32_t i = 0; i < type_.GetCount(); i++) {
596         if (!isFirst) {
597             text += TYPE_SEPARATOR + SPACE;
598         }
599         isFirst = false;
600         text += type_.GetObjectInfo(i).GetInfoString();
601     }
602     text += (SPACE + ARRAY_END);
603 }
604 
ProcessToText(std::string & text) const605 void PGOMethodTypeSet::ObjDefOpTypeInfo::ProcessToText(std::string &text) const
606 {
607     text += std::to_string(GetOffset());
608     text += BLOCK_START;
609     text += ARRAY_START + SPACE;
610     text += GetType().GetTypeString();
611     text += TYPE_SEPARATOR;
612     text += GetSuperType().GetTypeString();
613     text += (SPACE + ARRAY_END);
614 }
615 
AddMethod(Chunk * chunk,Method * jsMethod,SampleMode mode,int32_t incCount)616 bool PGOMethodInfoMap::AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode, int32_t incCount)
617 {
618     PGOMethodId methodId(jsMethod->GetMethodId());
619     auto result = methodInfos_.find(methodId);
620     if (result != methodInfos_.end()) {
621         auto info = result->second;
622         info->IncreaseCount(incCount);
623         info->SetSampleMode(mode);
624         return false;
625     } else {
626         CString methodName = jsMethod->GetMethodName();
627         size_t strlen = methodName.size();
628         size_t size = static_cast<size_t>(PGOMethodInfo::Size(strlen));
629         void *infoAddr = chunk->Allocate(size);
630         auto info = new (infoAddr) PGOMethodInfo(methodId, incCount, mode, methodName.c_str());
631         methodInfos_.emplace(methodId, info);
632         auto checksum = PGOMethodInfo::CalcChecksum(jsMethod->GetMethodName(), jsMethod->GetBytecodeArray(),
633                                                     jsMethod->GetCodeSize());
634         methodsChecksum_.emplace(methodId, checksum);
635         return true;
636     }
637 }
638 
GetOrInsertMethodTypeSet(Chunk * chunk,PGOMethodId methodId)639 PGOMethodTypeSet *PGOMethodInfoMap::GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId)
640 {
641     auto typeInfoSetIter = methodTypeInfos_.find(methodId);
642     if (typeInfoSetIter != methodTypeInfos_.end()) {
643         return typeInfoSetIter->second;
644     } else {
645         auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
646         methodTypeInfos_.emplace(methodId, typeInfoSet);
647         return typeInfoSet;
648     }
649 }
650 
AddType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)651 bool PGOMethodInfoMap::AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
652 {
653     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
654     ASSERT(typeInfoSet != nullptr);
655     typeInfoSet->AddType(offset, type);
656     return true;
657 }
658 
AddCallTargetType(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type)659 bool PGOMethodInfoMap::AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type)
660 {
661     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
662     ASSERT(typeInfoSet != nullptr);
663     typeInfoSet->AddCallTargetType(offset, type);
664     return true;
665 }
666 
AddObjectInfo(Chunk * chunk,PGOMethodId methodId,int32_t offset,const PGOObjectInfo & info)667 bool PGOMethodInfoMap::AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info)
668 {
669     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
670     ASSERT(typeInfoSet != nullptr);
671     typeInfoSet->AddObjectInfo(offset, info);
672     return true;
673 }
674 
AddDefine(Chunk * chunk,PGOMethodId methodId,int32_t offset,PGOSampleType type,PGOSampleType superType)675 bool PGOMethodInfoMap::AddDefine(
676     Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
677 {
678     auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
679     ASSERT(typeInfoSet != nullptr);
680     typeInfoSet->AddDefine(offset, type, superType);
681     return true;
682 }
683 
Merge(Chunk * chunk,PGOMethodInfoMap * methodInfos)684 void PGOMethodInfoMap::Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos)
685 {
686     for (auto iter = methodInfos->methodInfos_.begin(); iter != methodInfos->methodInfos_.end(); iter++) {
687         auto methodId = iter->first;
688         auto fromMethodInfo = iter->second;
689 
690         auto result = methodInfos_.find(methodId);
691         if (result != methodInfos_.end()) {
692             auto toMethodInfo = result->second;
693             toMethodInfo->Merge(fromMethodInfo);
694         } else {
695             size_t len = strlen(fromMethodInfo->GetMethodName());
696             size_t size = static_cast<size_t>(PGOMethodInfo::Size(len));
697             void *infoAddr = chunk->Allocate(size);
698             auto newMethodInfo = new (infoAddr) PGOMethodInfo(
699                 methodId, fromMethodInfo->GetCount(), fromMethodInfo->GetSampleMode(), fromMethodInfo->GetMethodName());
700             methodInfos_.emplace(methodId, newMethodInfo);
701         }
702         fromMethodInfo->ClearCount();
703     }
704 
705     for (auto iter = methodInfos->methodTypeInfos_.begin(); iter != methodInfos->methodTypeInfos_.end(); iter++) {
706         auto methodId = iter->first;
707         auto fromTypeInfo = iter->second;
708 
709         auto result = methodTypeInfos_.find(methodId);
710         if (result != methodTypeInfos_.end()) {
711             auto toTypeInfo = result->second;
712             toTypeInfo->Merge(fromTypeInfo);
713         } else {
714             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
715             typeInfoSet->Merge(fromTypeInfo);
716             methodTypeInfos_.emplace(methodId, typeInfoSet);
717         }
718     }
719 
720     for (auto iter = methodInfos->methodsChecksum_.begin(); iter != methodInfos->methodsChecksum_.end(); iter++) {
721         auto methodId = iter->first;
722         auto result = methodsChecksum_.find(methodId);
723         if (result == methodsChecksum_.end()) {
724             methodsChecksum_.emplace(methodId, iter->second);
725         }
726     }
727 }
728 
ParseFromBinary(Chunk * chunk,uint32_t threshold,void ** buffer,PGOProfilerHeader * const header)729 bool PGOMethodInfoMap::ParseFromBinary(Chunk *chunk, uint32_t threshold, void **buffer, PGOProfilerHeader *const header)
730 {
731     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
732     for (uint32_t j = 0; j < secInfo.number_; j++) {
733         PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
734         if (info->IsFilter(threshold)) {
735             if (header->SupportMethodChecksum()) {
736                 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
737             }
738             if (header->SupportType()) {
739                 PGOMethodTypeSet::SkipFromBinary(buffer);
740             }
741             continue;
742         }
743         methodInfos_.emplace(info->GetMethodId(), info);
744         LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << ELEMENT_SEPARATOR << info->GetCount()
745                         << ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
746                         << ELEMENT_SEPARATOR << info->GetMethodName();
747         if (header->SupportMethodChecksum()) {
748             auto checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
749             methodsChecksum_.emplace(info->GetMethodId(), checksum);
750         }
751         if (header->SupportType()) {
752             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
753             typeInfoSet->ParseFromBinary(buffer, header);
754             methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
755         }
756     }
757     return !methodInfos_.empty();
758 }
759 
ProcessToBinary(uint32_t threshold,const CString & recordName,const SaveTask * task,std::fstream & stream,PGOProfilerHeader * const header) const760 bool PGOMethodInfoMap::ProcessToBinary(uint32_t threshold, const CString &recordName, const SaveTask *task,
761     std::fstream &stream, PGOProfilerHeader *const header) const
762 {
763     SectionInfo secInfo;
764     std::stringstream methodStream;
765     for (auto iter = methodInfos_.begin(); iter != methodInfos_.end(); iter++) {
766         LOG_ECMA(DEBUG) << "Method:" << iter->first << ELEMENT_SEPARATOR << iter->second->GetCount()
767                         << ELEMENT_SEPARATOR << std::to_string(static_cast<int>(iter->second->GetSampleMode()))
768                         << ELEMENT_SEPARATOR << iter->second->GetMethodName();
769         if (task && task->IsTerminate()) {
770             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
771             return false;
772         }
773         auto curMethodInfo = iter->second;
774         if (curMethodInfo->IsFilter(threshold)) {
775             continue;
776         }
777         methodStream.write(reinterpret_cast<char *>(curMethodInfo), curMethodInfo->Size());
778         if (header->SupportMethodChecksum()) {
779             auto checksumIter = methodsChecksum_.find(curMethodInfo->GetMethodId());
780             uint32_t checksum = 0;
781             if (checksumIter != methodsChecksum_.end()) {
782                 checksum = checksumIter->second;
783             }
784             methodStream.write(reinterpret_cast<char *>(&checksum), sizeof(uint32_t));
785         }
786         if (header->SupportType()) {
787             auto typeInfoIter = methodTypeInfos_.find(curMethodInfo->GetMethodId());
788             if (typeInfoIter != methodTypeInfos_.end()) {
789                 typeInfoIter->second->ProcessToBinary(methodStream);
790             } else {
791                 uint32_t number = 0;
792                 methodStream.write(reinterpret_cast<char *>(&number), sizeof(uint32_t));
793             }
794         }
795         secInfo.number_++;
796     }
797     if (secInfo.number_ > 0) {
798         secInfo.offset_ = sizeof(SectionInfo);
799         secInfo.size_ = static_cast<uint32_t>(methodStream.tellg());
800         stream << recordName << '\0';
801         stream.write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo));
802         stream << methodStream.rdbuf();
803         return true;
804     }
805     return false;
806 }
807 
ParseFromText(Chunk * chunk,uint32_t threshold,const std::vector<std::string> & content)808 bool PGOMethodInfoMap::ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content)
809 {
810     for (auto infoString : content) {
811         std::vector<std::string> infoStrings = PGOMethodInfo::ParseFromText(infoString);
812         if (infoStrings.size() < PGOMethodInfo::METHOD_INFO_COUNT) {
813             LOG_ECMA(ERROR) << "method info:" << infoString << " format error";
814             return false;
815         }
816         uint32_t count;
817         if (!base::StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX].c_str(), &count)) {
818             LOG_ECMA(ERROR) << "count: " << infoStrings[PGOMethodInfo::METHOD_COUNT_INDEX] << " parse failed";
819             return false;
820         }
821         SampleMode mode;
822         if (!PGOMethodInfo::GetSampleMode(infoStrings[PGOMethodInfo::METHOD_MODE_INDEX], mode)) {
823             LOG_ECMA(ERROR) << "mode: " << infoStrings[PGOMethodInfo::METHOD_MODE_INDEX] << " parse failed";
824             return false;
825         }
826         if (count < threshold && mode == SampleMode::CALL_MODE) {
827             return true;
828         }
829         uint32_t methodId;
830         if (!base::StringHelper::StrToUInt32(infoStrings[PGOMethodInfo::METHOD_ID_INDEX].c_str(), &methodId)) {
831             LOG_ECMA(ERROR) << "method id: " << infoStrings[PGOMethodInfo::METHOD_ID_INDEX] << " parse failed";
832             return false;
833         }
834         std::string methodName = infoStrings[PGOMethodInfo::METHOD_NAME_INDEX];
835 
836         size_t len = methodName.size();
837         void *infoAddr = chunk->Allocate(PGOMethodInfo::Size(len));
838         auto info = new (infoAddr) PGOMethodInfo(PGOMethodId(methodId), count, mode, methodName.c_str());
839         methodInfos_.emplace(methodId, info);
840 
841         // Parse Type Info
842         if (infoStrings.size() <= PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX) {
843             continue;
844         }
845         std::string typeInfos = infoStrings[PGOMethodTypeSet::METHOD_TYPE_INFO_INDEX];
846         if (!typeInfos.empty()) {
847             size_t start = typeInfos.find_first_of(ARRAY_START);
848             size_t end = typeInfos.find_last_of(ARRAY_END);
849             if (start == std::string::npos || end == std::string::npos || start > end) {
850                 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
851                 return false;
852             }
853             auto typeContent = typeInfos.substr(start + 1, end - (start + 1) - 1);
854             auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
855             if (!typeInfoSet->ParseFromText(typeContent)) {
856                 // delete by chunk
857                 LOG_ECMA(ERROR) << "Type info: " << typeInfos << " parse failed";
858                 return false;
859             }
860             methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
861         }
862     }
863 
864     return true;
865 }
866 
ProcessToText(uint32_t threshold,const CString & recordName,std::ofstream & stream) const867 void PGOMethodInfoMap::ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const
868 {
869     std::string profilerString;
870     bool isFirst = true;
871     for (auto methodInfoIter : methodInfos_) {
872         auto methodInfo = methodInfoIter.second;
873         if (methodInfo->IsFilter(threshold)) {
874             continue;
875         }
876         if (isFirst) {
877             profilerString += NEW_LINE;
878             profilerString += recordName;
879             profilerString += BLOCK_AND_ARRAY_START;
880             isFirst = false;
881         } else {
882             profilerString += BLOCK_SEPARATOR + SPACE;
883         }
884         methodInfo->ProcessToText(profilerString);
885         profilerString += ELEMENT_SEPARATOR;
886         auto checksumIter = methodsChecksum_.find(methodInfo->GetMethodId());
887         if (checksumIter != methodsChecksum_.end()) {
888             std::stringstream parseStream;
889             parseStream << std::internal << std::setfill('0') << std::showbase << std::setw(HEX_FORMAT_WIDTH_FOR_32BITS)
890                         << std::hex << checksumIter->second << ELEMENT_SEPARATOR;
891             profilerString += parseStream.str();
892         }
893         auto iter = methodTypeInfos_.find(methodInfo->GetMethodId());
894         if (iter != methodTypeInfos_.end()) {
895             iter->second->ProcessToText(profilerString);
896         }
897     }
898     if (!isFirst) {
899         profilerString += (SPACE + ARRAY_END + NEW_LINE);
900         stream << profilerString;
901     }
902 }
903 
ParseFromBinary(uint32_t threshold,void ** buffer,PGOProfilerHeader * const header)904 bool PGOMethodIdSet::ParseFromBinary(uint32_t threshold, void **buffer, PGOProfilerHeader *const header)
905 {
906     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
907     for (uint32_t j = 0; j < secInfo.number_; j++) {
908         PGOMethodInfo *info = base::ReadBufferInSize<PGOMethodInfo>(buffer);
909         if (info->IsFilter(threshold)) {
910             if (header->SupportMethodChecksum()) {
911                 base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
912             }
913             if (header->SupportType()) {
914                 PGOMethodTypeSet::SkipFromBinary(buffer);
915             }
916             continue;
917         }
918         uint32_t checksum = 0;
919         if (header->SupportMethodChecksum()) {
920             checksum = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
921         }
922         auto ret = methodInfoMap_.try_emplace(info->GetMethodName(), chunk_);
923         auto methodNameSetIter = ret.first;
924         auto &methodInfo = methodNameSetIter->second.GetOrCreateMethodInfo(checksum, info->GetMethodId());
925         LOG_ECMA(DEBUG) << "Method:" << info->GetMethodId() << ELEMENT_SEPARATOR << info->GetCount()
926                         << ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
927                         << ELEMENT_SEPARATOR << info->GetMethodName();
928         if (header->SupportType()) {
929             methodInfo.GetPGOMethodTypeSet().ParseFromBinary(buffer, header);
930         }
931     }
932 
933     return !methodInfoMap_.empty();
934 }
935 
GetMismatchResult(const CString & recordName,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet) const936 void PGOMethodIdSet::GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount,
937                                        uint32_t &mismatchMethodCount,
938                                        std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
939 {
940     totalMethodCount += methodInfoMap_.size();
941     for (const auto &methodNameSet : methodInfoMap_) {
942         if (methodNameSet.second.IsMatch()) {
943             continue;
944         }
945         auto info = std::make_pair(methodNameSet.first, recordName);
946         mismatchMethodSet.emplace(info);
947         mismatchMethodCount++;
948     }
949 }
950 
Merge(const PGOMethodIdSet & from)951 void PGOMethodIdSet::Merge(const PGOMethodIdSet &from)
952 {
953     for (const auto &methodNameSet : from.methodInfoMap_) {
954         auto iter = methodInfoMap_.find(methodNameSet.first);
955         if (iter == methodInfoMap_.end()) {
956             auto ret = methodInfoMap_.try_emplace(methodNameSet.first, chunk_);
957             iter = ret.first;
958         }
959         const_cast<PGOMethodNameSet &>(iter->second).Merge(methodNameSet.second);
960     }
961 }
962 
Merge(const PGODecodeMethodInfo & from)963 void PGODecodeMethodInfo::Merge(const PGODecodeMethodInfo &from)
964 {
965     ASSERT(methodId_.IsValid() && from.methodId_.IsValid());
966     if (!(methodId_ == from.methodId_)) {
967         LOG_ECMA(ERROR) << "MethodId not match. " << methodId_ << " vs " << from.methodId_;
968         return;
969     }
970     pgoMethodTypeSet_.Merge(&from.pgoMethodTypeSet_);
971 }
972 
GetMethodInfoMap(const CString & recordName)973 PGOMethodInfoMap *PGORecordDetailInfos::GetMethodInfoMap(const CString &recordName)
974 {
975     auto iter = recordInfos_.find(recordName.c_str());
976     if (iter != recordInfos_.end()) {
977         return iter->second;
978     } else {
979         auto curMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
980         recordInfos_.emplace(recordName.c_str(), curMethodInfos);
981         return curMethodInfos;
982     }
983 }
984 
AddMethod(const CString & recordName,Method * jsMethod,SampleMode mode,int32_t incCount)985 bool PGORecordDetailInfos::AddMethod(const CString &recordName, Method *jsMethod, SampleMode mode, int32_t incCount)
986 {
987     auto curMethodInfos = GetMethodInfoMap(recordName);
988     ASSERT(curMethodInfos != nullptr);
989     ASSERT(jsMethod != nullptr);
990     return curMethodInfos->AddMethod(chunk_.get(), jsMethod, mode, incCount);
991 }
992 
AddType(const CString & recordName,PGOMethodId methodId,int32_t offset,PGOSampleType type)993 bool PGORecordDetailInfos::AddType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type)
994 {
995     auto curMethodInfos = GetMethodInfoMap(recordName);
996     ASSERT(curMethodInfos != nullptr);
997     return curMethodInfos->AddType(chunk_.get(), methodId, offset, type);
998 }
999 
AddCallTargetType(const CString & recordName,PGOMethodId methodId,int32_t offset,PGOSampleType type)1000 bool PGORecordDetailInfos::AddCallTargetType(const CString &recordName, PGOMethodId methodId, int32_t offset,
1001                                              PGOSampleType type)
1002 {
1003     auto curMethodInfos = GetMethodInfoMap(recordName);
1004     ASSERT(curMethodInfos != nullptr);
1005     return curMethodInfos->AddCallTargetType(chunk_.get(), methodId, offset, type);
1006 }
1007 
AddObjectInfo(const CString & recordName,EntityId methodId,int32_t offset,const PGOObjectInfo & info)1008 bool PGORecordDetailInfos::AddObjectInfo(
1009     const CString &recordName, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
1010 {
1011     auto curMethodInfos = GetMethodInfoMap(recordName);
1012     ASSERT(curMethodInfos != nullptr);
1013     return curMethodInfos->AddObjectInfo(chunk_.get(), methodId, offset, info);
1014 }
1015 
AddDefine(const CString & recordName,PGOMethodId methodId,int32_t offset,PGOSampleType type,PGOSampleType superType)1016 bool PGORecordDetailInfos::AddDefine(
1017     const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
1018 {
1019     auto curMethodInfos = GetMethodInfoMap(recordName);
1020     ASSERT(curMethodInfos != nullptr);
1021     curMethodInfos->AddDefine(chunk_.get(), methodId, offset, type, superType);
1022 
1023     PGOHClassLayoutDesc descInfo(type.GetClassType());
1024     descInfo.SetSuperClassType(superType.GetClassType());
1025     auto iter = moduleLayoutDescInfos_.find(descInfo);
1026     if (iter != moduleLayoutDescInfos_.end()) {
1027         moduleLayoutDescInfos_.erase(iter);
1028     }
1029     moduleLayoutDescInfos_.emplace(descInfo);
1030     return true;
1031 }
1032 
AddLayout(PGOSampleType type,JSTaggedType hclass,PGOObjKind kind)1033 bool PGORecordDetailInfos::AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjKind kind)
1034 {
1035     auto hclassObject = JSHClass::Cast(JSTaggedValue(hclass).GetTaggedObject());
1036     PGOHClassLayoutDesc descInfo(type.GetClassType());
1037     auto iter = moduleLayoutDescInfos_.find(descInfo);
1038     if (iter != moduleLayoutDescInfos_.end()) {
1039         auto &oldDescInfo = const_cast<PGOHClassLayoutDesc &>(*iter);
1040         if (!JSHClass::DumpForProfile(hclassObject, oldDescInfo, kind)) {
1041             return false;
1042         }
1043     } else {
1044         LOG_ECMA(DEBUG) << "The current class did not find a definition";
1045         return false;
1046     }
1047     return true;
1048 }
1049 
Merge(const PGORecordDetailInfos & recordInfos)1050 void PGORecordDetailInfos::Merge(const PGORecordDetailInfos &recordInfos)
1051 {
1052     for (auto iter = recordInfos.recordInfos_.begin(); iter != recordInfos.recordInfos_.end(); iter++) {
1053         auto recordName = iter->first;
1054         auto fromMethodInfos = iter->second;
1055 
1056         auto recordInfosIter = recordInfos_.find(recordName);
1057         PGOMethodInfoMap *toMethodInfos = nullptr;
1058         if (recordInfosIter == recordInfos_.end()) {
1059             toMethodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
1060             recordInfos_.emplace(recordName, toMethodInfos);
1061         } else {
1062             toMethodInfos = recordInfosIter->second;
1063         }
1064 
1065         toMethodInfos->Merge(chunk_.get(), fromMethodInfos);
1066     }
1067     // Merge global layout desc infos to global method info map
1068     for (auto info = recordInfos.moduleLayoutDescInfos_.begin(); info != recordInfos.moduleLayoutDescInfos_.end();
1069          info++) {
1070         auto result = moduleLayoutDescInfos_.find(*info);
1071         if (result == moduleLayoutDescInfos_.end()) {
1072             moduleLayoutDescInfos_.emplace(*info);
1073         } else {
1074             const_cast<PGOHClassLayoutDesc &>(*result).Merge(*info);
1075         }
1076     }
1077 }
1078 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header)1079 void PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
1080 {
1081     SectionInfo *info = header->GetRecordInfoSection();
1082     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
1083     for (uint32_t i = 0; i < info->number_; i++) {
1084         auto recordName = base::ReadBuffer(&addr);
1085         PGOMethodInfoMap *methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
1086         if (methodInfos->ParseFromBinary(chunk_.get(), hotnessThreshold_, &addr, header)) {
1087             recordInfos_.emplace(recordName, methodInfos);
1088         }
1089     }
1090 
1091     info = header->GetLayoutDescSection();
1092     if (info == nullptr) {
1093         return;
1094     }
1095     if (header->SupportTrackField()) {
1096         ParseFromBinaryForLayout(&addr, header);
1097     }
1098 }
1099 
ParseFromBinaryForLayout(void ** buffer,PGOProfilerHeader * const header)1100 bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header)
1101 {
1102     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
1103     for (uint32_t i = 0; i < secInfo.number_; i++) {
1104         PGOHClassLayoutDescInner *info = base::ReadBufferInSize<PGOHClassLayoutDescInner>(buffer);
1105         if (info == nullptr) {
1106             LOG_ECMA(INFO) << "Binary format error!";
1107             continue;
1108         }
1109         moduleLayoutDescInfos_.emplace(info->Convert(header));
1110     }
1111     return true;
1112 }
1113 
ProcessToBinary(const SaveTask * task,std::fstream & fileStream,PGOProfilerHeader * const header) const1114 void PGORecordDetailInfos::ProcessToBinary(
1115     const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header) const
1116 {
1117     auto info = header->GetRecordInfoSection();
1118     info->number_ = 0;
1119     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
1120     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
1121         if (task && task->IsTerminate()) {
1122             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
1123             break;
1124         }
1125         auto recordName = iter->first;
1126         auto curMethodInfos = iter->second;
1127         if (curMethodInfos->ProcessToBinary(hotnessThreshold_, recordName, task, fileStream, header)) {
1128             info->number_++;
1129         }
1130     }
1131     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
1132 
1133     info = header->GetLayoutDescSection();
1134     if (info == nullptr) {
1135         return;
1136     }
1137     info->number_ = 0;
1138     info->offset_ = static_cast<uint32_t>(fileStream.tellp());
1139     if (header->SupportType()) {
1140         if (!ProcessToBinaryForLayout(const_cast<NativeAreaAllocator *>(&nativeAreaAllocator_), task, fileStream)) {
1141             return;
1142         }
1143         info->number_++;
1144     }
1145     info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_;
1146     header->SetFileSize(static_cast<uint32_t>(fileStream.tellp()));
1147 }
1148 
ProcessToBinaryForLayout(NativeAreaAllocator * allocator,const SaveTask * task,std::fstream & stream) const1149 bool PGORecordDetailInfos::ProcessToBinaryForLayout(
1150     NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream) const
1151 {
1152     SectionInfo secInfo;
1153     auto layoutBeginPosition = stream.tellp();
1154     stream.seekp(sizeof(SectionInfo), std::ofstream::cur);
1155     for (const auto &typeInfo : moduleLayoutDescInfos_) {
1156         if (task && task->IsTerminate()) {
1157             LOG_ECMA(DEBUG) << "ProcessProfile: task is already terminate";
1158             return false;
1159         }
1160         auto classType = PGOSampleType(typeInfo.GetClassType());
1161         auto elementsKind = typeInfo.GetElementsKind();
1162         size_t size = PGOHClassLayoutDescInner::CaculateSize(typeInfo);
1163         if (size == 0) {
1164             continue;
1165         }
1166         auto superType = PGOSampleType(typeInfo.GetSuperClassType());
1167         void *addr = allocator->Allocate(size);
1168         auto descInfos = new (addr) PGOHClassLayoutDescInner(size, classType, superType, elementsKind);
1169         descInfos->Merge(typeInfo);
1170         stream.write(reinterpret_cast<char *>(descInfos), size);
1171         allocator->Delete(addr);
1172         secInfo.number_++;
1173     }
1174 
1175     secInfo.offset_ = sizeof(SectionInfo);
1176     secInfo.size_ = static_cast<uint32_t>(stream.tellp()) -
1177         static_cast<uint32_t>(layoutBeginPosition) - sizeof(SectionInfo);
1178     stream.seekp(layoutBeginPosition, std::ofstream::beg)
1179         .write(reinterpret_cast<char *>(&secInfo), sizeof(SectionInfo))
1180         .seekp(0, std::ofstream::end);
1181     return true;
1182 }
1183 
ParseFromText(std::ifstream & stream)1184 bool PGORecordDetailInfos::ParseFromText(std::ifstream &stream)
1185 {
1186     std::string details;
1187     while (std::getline(stream, details)) {
1188         if (details.empty()) {
1189             continue;
1190         }
1191         size_t blockIndex = details.find(BLOCK_AND_ARRAY_START);
1192         if (blockIndex == std::string::npos) {
1193             return false;
1194         }
1195         CString recordName = ConvertToString(details.substr(0, blockIndex));
1196 
1197         size_t start = details.find_first_of(ARRAY_START);
1198         size_t end = details.find_last_of(ARRAY_END);
1199         if (start == std::string::npos || end == std::string::npos || start > end) {
1200             return false;
1201         }
1202         auto content = details.substr(start + 1, end - (start + 1) - 1);
1203         std::vector<std::string> infoStrings = base::StringHelper::SplitString(content, BLOCK_SEPARATOR);
1204         if (infoStrings.size() <= 0) {
1205             continue;
1206         }
1207 
1208         auto methodInfosIter = recordInfos_.find(recordName.c_str());
1209         PGOMethodInfoMap *methodInfos = nullptr;
1210         if (methodInfosIter == recordInfos_.end()) {
1211             methodInfos = nativeAreaAllocator_.New<PGOMethodInfoMap>();
1212             recordInfos_.emplace(recordName.c_str(), methodInfos);
1213         } else {
1214             methodInfos = methodInfosIter->second;
1215         }
1216         if (!methodInfos->ParseFromText(chunk_.get(), hotnessThreshold_, infoStrings)) {
1217             return false;
1218         }
1219     }
1220     return true;
1221 }
1222 
ProcessToText(std::ofstream & stream) const1223 void PGORecordDetailInfos::ProcessToText(std::ofstream &stream) const
1224 {
1225     std::string profilerString;
1226     bool isFirst = true;
1227     for (auto layoutInfoIter : moduleLayoutDescInfos_) {
1228         if (isFirst) {
1229             profilerString += NEW_LINE;
1230             profilerString += ARRAY_START + SPACE;
1231             isFirst = false;
1232         } else {
1233             profilerString += BLOCK_SEPARATOR + SPACE;
1234         }
1235         profilerString += PGOHClassLayoutDescInner::GetTypeString(layoutInfoIter);
1236     }
1237     if (!isFirst) {
1238         profilerString += (SPACE + ARRAY_END + NEW_LINE);
1239         stream << profilerString;
1240     }
1241     for (auto iter = recordInfos_.begin(); iter != recordInfos_.end(); iter++) {
1242         auto recordName = iter->first;
1243         auto methodInfos = iter->second;
1244         methodInfos->ProcessToText(hotnessThreshold_, recordName, stream);
1245     }
1246 }
1247 
Match(const CString & recordName,EntityId methodId)1248 bool PGORecordSimpleInfos::Match(const CString &recordName, EntityId methodId)
1249 {
1250     auto methodIdsIter = methodIds_.find(recordName);
1251     if (methodIdsIter == methodIds_.end()) {
1252         return false;
1253     }
1254     return methodIdsIter->second->Match(methodId);
1255 }
1256 
ParseFromBinary(void * buffer,PGOProfilerHeader * const header)1257 void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *const header)
1258 {
1259     SectionInfo *info = header->GetRecordInfoSection();
1260     void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_);
1261     for (uint32_t i = 0; i < info->number_; i++) {
1262         auto recordName = base::ReadBuffer(&addr);
1263         PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1264         if (methodIds->ParseFromBinary(hotnessThreshold_, &addr, header)) {
1265             methodIds_.emplace(recordName, methodIds);
1266         }
1267     }
1268 
1269     info = header->GetLayoutDescSection();
1270     if (info == nullptr) {
1271         return;
1272     }
1273     if (header->SupportTrackField()) {
1274         ParseFromBinaryForLayout(&addr, header);
1275     }
1276 }
1277 
Merge(const PGORecordSimpleInfos & simpleInfos)1278 void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
1279 {
1280     for (const auto &method : simpleInfos.methodIds_) {
1281         auto result = methodIds_.find(method.first);
1282         if (result == methodIds_.end()) {
1283             PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1284             auto ret = methodIds_.emplace(method.first, methodIds);
1285             ASSERT(ret.second);
1286             result = ret.first;
1287         }
1288         const_cast<PGOMethodIdSet &>(*result->second).Merge(*method.second);
1289     }
1290     // Merge global layout desc infos to global method info map
1291     for (const auto &moduleLayoutDescInfo : simpleInfos.moduleLayoutDescInfos_) {
1292         auto result = moduleLayoutDescInfos_.find(moduleLayoutDescInfo);
1293         if (result == moduleLayoutDescInfos_.end()) {
1294             moduleLayoutDescInfos_.emplace(moduleLayoutDescInfo);
1295         } else {
1296             const_cast<PGOHClassLayoutDesc &>(*result).Merge(moduleLayoutDescInfo);
1297         }
1298     }
1299 }
1300 
ParseFromBinaryForLayout(void ** buffer,PGOProfilerHeader * const header)1301 bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header)
1302 {
1303     SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
1304     for (uint32_t i = 0; i < secInfo.number_; i++) {
1305         PGOHClassLayoutDescInner *info = base::ReadBufferInSize<PGOHClassLayoutDescInner>(buffer);
1306         if (info == nullptr) {
1307             LOG_ECMA(INFO) << "Binary format error!";
1308             continue;
1309         }
1310         moduleLayoutDescInfos_.emplace(info->Convert(header));
1311     }
1312     return true;
1313 }
1314 } // namespace panda::ecmascript
1315