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