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 #ifndef ECMASCRIPT_PGO_PROFILER_AP_FILE_BASE_INFO_H 17 #define ECMASCRIPT_PGO_PROFILER_AP_FILE_BASE_INFO_H 18 19 #include <cstdint> 20 21 #include "ecmascript/common.h" 22 #include "libpandafile/file.h" 23 #include "macros.h" 24 25 #include "ecmascript/base/file_header.h" 26 #include "ecmascript/compiler/aot_file/aot_version.h" 27 #include "ecmascript/pgo_profiler/pgo_context.h" 28 29 namespace panda::ecmascript::pgo { 30 class PGOProfilerHeader; 31 32 struct SectionInfo { 33 uint32_t offset_ {0}; 34 // reserve 35 uint32_t size_ {0}; 36 uint32_t number_ {0}; 37 }; 38 39 /** 40 |----PGOProfilerHeader 41 |--------MAGIC(8) 42 |------------{ 'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0' } 43 |--------VERSION(4) 44 |------------{ '0', '0', '0', '0' } 45 |--------CHECKSUM(4) 46 |------------{ checksum } 47 |--------FILE_SIZE(4) 48 |------------{ fileSize } 49 |--------HEADER_SIZE(4) 50 |------------{ headerSize, from MAGIC to SECTION_NUMBER } 51 |--------ENDIAN_TAG(4) 52 |------------{ ENDIAN_TAG } 53 |--------SECTION_NUMBER(4) 54 |------------{ 4 } 55 |--------PANDA_FILE_INFO_SECTION_INFO(12) 56 |------------{ offset, size (reserve), number1 } 57 |--------RECORD_INFO_SECTION_INFO(12) 58 |------------{ offset, size (reserve), number2 } 59 |--------LAYOUT_DESC_SECTION_INFO(12) 60 |------------{ offset, size (reserve), number3 } 61 |--------RECORD_POOL(12) 62 |------------{ offset, size (reserve), recordPoolCount } 63 |--------PROTO_TRANSITION_POOL(12) 64 |------------{ offset, size (reserve), protoTransitionPoolCount } 65 | 66 |----Section1: PGOPandaFileInfos(number1) 67 |--------[{ size, CHECK_SUM }, { size, CHECK_SUM }, ...] 68 | 69 |----Section2: PGORecordDetailInfos(number2) 70 |--------[ PGOMethodInfoMap(number4) 71 |------------{ recordId, offset, size, number4 } 72 |------------[ PGOMethodInfo(size1) 73 |----------------{ size1, entityId, count, mode, methodName, 74 |-------------------- [{ size, offset, profileTypeId }, { size, offset, profileTypeId }, ...]}, 75 |------------ PGOMethodInfo(size1) 76 |----------------{ size1, entityId, count, mode, methodName, 77 |-------------------- [{ size, offset, profileTypeId }, { size, offset, profileTypeId }, ...]}, 78 |--------------... ] 79 |-------- PGOMethodInfoMap() 80 |--------... ] 81 | 82 |----Section3: PGHClassLayoutDescs(number3) 83 |--------{ offset, size, number5 } 84 |--------[ PGOHClassLayoutDescInner(size) 85 |------------{ size, profileTypeId, superProfileTypeId, count, ptCount, ctorCount, 86 |---------------- [{ size, handle, key }, { size, heandle, key }, ...]} 87 |-------- PGOHClassLayoutDescInner(size) 88 |------------{ size, profileTypeId, superProfileTypeId, count, ptCount, ctorCount, 89 |---------------- [{ size, handle, key }, { size, heandle, key }, ...]} 90 | 91 |----Section4: PGORecord(recordPoolCount) 92 |--------{ offset, size, recordItemCount } 93 |--------[ recordId, recordName ](recordItemCount) 94 | 95 |----Section5: PGOProtoTransitionTypes(protoTransitionPoolCount) 96 |--------{ offset, size, protoTransitionItemCount } 97 |--------[ PGOProtoTransitionType ](protoTransitionItemCount) 98 | 99 |----Section6: ProfileTypes(ProfileTypePoolCount) 100 |--------{ offset, size, profileTypeItemCount } 101 |--------[ profileTypeId, profileType(64bit) ](profileTypeItemCount) 102 */ 103 class PGOProfilerHeader : public base::FileHeaderElastic { 104 public: 105 static constexpr VersionType TYPE_MINI_VERSION = {0, 0, 0, 2}; 106 static constexpr VersionType METHOD_CHECKSUM_MINI_VERSION = {0, 0, 0, 4}; 107 static constexpr VersionType USE_HCLASS_TYPE_MINI_VERSION = {0, 0, 0, 5}; 108 static constexpr VersionType FILE_CONSISTENCY_MINI_VERSION = {0, 0, 0, 6}; 109 static constexpr VersionType TRACK_FIELD_MINI_VERSION = {0, 0, 0, 7}; 110 static constexpr VersionType ELEMENTS_KIND_MINI_VERSION = {0, 0, 0, 8}; 111 static constexpr VersionType RECORD_POOL_MINI_VERSION = {0, 0, 0, 9}; 112 static constexpr VersionType WIDE_CLASS_TYPE_MINI_VERSION = {0, 0, 0, 10}; 113 static constexpr VersionType PROFILE_TYPE_WITH_ABC_ID_MINI_VERSION = {0, 0, 0, 11}; 114 static constexpr VersionType ELEMENTS_TRACK_INFO_MINI_VERSION = {0, 0, 0, 12}; 115 static constexpr VersionType PROTO_TRANSITION_POOL_MINI_VERSION = {0, 0, 0, 14}; 116 static constexpr VersionType MULTI_ABC_CHECKSUM_MINI_VERSION = {0, 0, 0, 15}; 117 static constexpr VersionType FILE_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 118 static constexpr VersionType HEADER_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 119 static constexpr VersionType ELASTIC_HEADER_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 120 static constexpr VersionType LAST_VERSION = {0, 0, 0, 15}; 121 static constexpr size_t PANDA_FILE_SECTION_INDEX = 0; 122 static constexpr size_t RECORD_INFO_SECTION_INDEX = 1; 123 static constexpr size_t LAYOUT_DESC_SECTION_INDEX = 2; 124 static constexpr size_t RECORD_POOL_SECTION_INDEX = 3; 125 static constexpr size_t PROTO_TRANSITION_POOL_SECTION_INDEX = 4; 126 static constexpr size_t CLASS_TYPE_POOL_SECTION_INDEX = 5; 127 static constexpr size_t ABC_FILE_POOL_SECTION_INDEX = 6; 128 static constexpr size_t SECTION_SIZE = 7; 129 PGOProfilerHeader()130 PGOProfilerHeader() : base::FileHeaderElastic(LAST_VERSION), sectionNumber_(SECTION_SIZE) 131 { 132 GetPandaInfoSection()->offset_ = Size(); 133 SetHeaderSize(Size()); 134 } 135 LastSize()136 static size_t LastSize() 137 { 138 return sizeof(PGOProfilerHeader) + (SECTION_SIZE - 1) * sizeof(SectionInfo); 139 } 140 Size(uint32_t sectionNumber)141 static size_t Size(uint32_t sectionNumber) 142 { 143 ASSERT(sectionNumber > 0); 144 return sizeof(PGOProfilerHeader) + (sectionNumber - 1) * sizeof(SectionInfo); 145 } 146 Size()147 size_t Size() const 148 { 149 return Size(sectionNumber_); 150 } 151 Verify()152 bool Verify() const 153 { 154 return VerifyVersion("apPath file", LAST_VERSION, IsStrictMatch()); 155 } 156 Verify(void * buffer,size_t bufferSize)157 bool Verify(void *buffer, size_t bufferSize) const 158 { 159 if (!Verify()) { 160 return false; 161 } 162 if (!VerifyConsistency(buffer, bufferSize)) { 163 return false; 164 } 165 if (!VerifyFileSize(bufferSize)) { 166 return false; 167 } 168 return true; 169 } 170 171 bool VerifyFileSize(size_t bufferSize) const; 172 173 bool VerifyConsistency(void *buffer, size_t bufferSize) const; 174 Build(PGOProfilerHeader ** header,size_t size)175 static void Build(PGOProfilerHeader **header, size_t size) 176 { 177 void* rawMemory = malloc(size); 178 if (rawMemory == nullptr) { 179 LOG_ECMA(FATAL) << "Failed to apply for memory, size :" << size; 180 UNREACHABLE(); 181 } 182 *header = reinterpret_cast<PGOProfilerHeader *>(rawMemory); 183 new (*header) PGOProfilerHeader(); 184 } 185 Destroy(PGOProfilerHeader ** header)186 static void Destroy(PGOProfilerHeader **header) 187 { 188 if (*header != nullptr) { 189 free(*header); 190 *header = nullptr; 191 } 192 } 193 194 // Copy Header. 195 static bool ParseFromBinary(void *buffer, size_t bufferSize, PGOProfilerHeader **header); 196 void ProcessToBinary(std::fstream &fileStream) const; 197 198 bool ProcessToText(std::ofstream &stream) const; 199 GetPandaInfoSection()200 SectionInfo *GetPandaInfoSection() const 201 { 202 return GetSectionInfo(PANDA_FILE_SECTION_INDEX); 203 } 204 GetRecordInfoSection()205 SectionInfo *GetRecordInfoSection() const 206 { 207 return GetSectionInfo(RECORD_INFO_SECTION_INDEX); 208 } 209 GetLayoutDescSection()210 SectionInfo *GetLayoutDescSection() const 211 { 212 return GetSectionInfo(LAYOUT_DESC_SECTION_INDEX); 213 } 214 GetRecordPoolSection()215 SectionInfo *GetRecordPoolSection() const 216 { 217 return GetSectionInfo(RECORD_POOL_SECTION_INDEX); 218 } 219 GetProfileTypeSection()220 SectionInfo *GetProfileTypeSection() const 221 { 222 return GetSectionInfo(CLASS_TYPE_POOL_SECTION_INDEX); 223 } 224 GetAbcFilePoolSection()225 SectionInfo *GetAbcFilePoolSection() const 226 { 227 return GetSectionInfo(ABC_FILE_POOL_SECTION_INDEX); 228 } 229 GetProtoTransitionPoolSection()230 SectionInfo *GetProtoTransitionPoolSection() const 231 { 232 return GetSectionInfo(PROTO_TRANSITION_POOL_SECTION_INDEX); 233 } 234 SupportType()235 bool SupportType() const 236 { 237 return CompatibleVerify(TYPE_MINI_VERSION); 238 } 239 SupportMethodChecksum()240 bool SupportMethodChecksum() const 241 { 242 return CompatibleVerify(METHOD_CHECKSUM_MINI_VERSION); 243 } 244 SupportUseHClassType()245 bool SupportUseHClassType() const 246 { 247 return CompatibleVerify(USE_HCLASS_TYPE_MINI_VERSION); 248 } 249 SupportProtoTransitionPool()250 bool SupportProtoTransitionPool() const 251 { 252 return CompatibleVerify(PROTO_TRANSITION_POOL_MINI_VERSION); 253 } 254 SupportFileConsistency()255 bool SupportFileConsistency() const 256 { 257 return CompatibleVerify(FILE_CONSISTENCY_MINI_VERSION); 258 } 259 SupportFileSize()260 bool SupportFileSize() const 261 { 262 return CompatibleVerify(FILE_SIZE_MINI_VERSION); 263 } 264 SupportHeaderSize()265 bool SupportHeaderSize() const 266 { 267 return CompatibleVerify(HEADER_SIZE_MINI_VERSION); 268 } 269 SupportTrackField()270 bool SupportTrackField() const 271 { 272 return CompatibleVerify(TRACK_FIELD_MINI_VERSION); 273 } 274 SupportElementsKind()275 bool SupportElementsKind() const 276 { 277 return CompatibleVerify(ELEMENTS_KIND_MINI_VERSION); 278 } 279 SupportRecordPool()280 bool SupportRecordPool() const 281 { 282 return CompatibleVerify(RECORD_POOL_MINI_VERSION); 283 } 284 SupportWideProfileType()285 bool SupportWideProfileType() const 286 { 287 return CompatibleVerify(WIDE_CLASS_TYPE_MINI_VERSION); 288 } 289 SupportProfileTypeWithAbcId()290 bool SupportProfileTypeWithAbcId() const 291 { 292 return CompatibleVerify(PROFILE_TYPE_WITH_ABC_ID_MINI_VERSION); 293 } 294 SupportElementsTrackInfo()295 bool SupportElementsTrackInfo() const 296 { 297 return CompatibleVerify(ELEMENTS_TRACK_INFO_MINI_VERSION); 298 } 299 SupportMultiAbcChecksum()300 bool SupportMultiAbcChecksum() const 301 { 302 return CompatibleVerify(MULTI_ABC_CHECKSUM_MINI_VERSION); 303 } 304 IsCompatibleWithAOTFile()305 bool IsCompatibleWithAOTFile() const 306 { 307 return VerifyVersion("ap file compatible aot file", GetCompatibleAnVersion(), AOTFileVersion::AN_VERSION, true); 308 } 309 IsStrictMatch()310 static bool IsStrictMatch() 311 { 312 return strictMatch_; 313 } 314 IschecksumListHasAbcId()315 static bool IschecksumListHasAbcId() 316 { 317 return checksumListHasAbcId_; 318 } 319 320 // just for test SetStrictMatch(bool strictMatch)321 static void SetStrictMatch(bool strictMatch) 322 { 323 strictMatch_ = strictMatch; 324 } 325 326 // just for test SetchecksumListHasAbcId(bool checksumListHasAbcId)327 static void SetchecksumListHasAbcId(bool checksumListHasAbcId) 328 { 329 checksumListHasAbcId_ = checksumListHasAbcId; 330 } 331 332 NO_COPY_SEMANTIC(PGOProfilerHeader); 333 NO_MOVE_SEMANTIC(PGOProfilerHeader); 334 335 private: 336 static bool BuildFromLegacy(void *buffer, PGOProfilerHeader **header); 337 static bool BuildFromElastic(void *buffer, size_t bufferSize, PGOProfilerHeader **header); 338 GetSectionInfo(size_t index)339 SectionInfo *GetSectionInfo(size_t index) const 340 { 341 if (index >= sectionNumber_) { 342 return nullptr; 343 } 344 return const_cast<SectionInfo *>(§ionInfos_) + index; 345 } 346 347 uint32_t sectionNumber_ {SECTION_SIZE}; 348 SectionInfo sectionInfos_; 349 static bool strictMatch_; 350 static bool checksumListHasAbcId_; 351 }; 352 353 class PGOProfilerHeaderLegacy : public base::FileHeaderBase { 354 public: 355 static constexpr size_t SECTION_SIZE = 3; 356 static constexpr VersionType LAST_VERSION = {0, 0, 0, 5}; PGOProfilerHeaderLegacy()357 PGOProfilerHeaderLegacy() : base::FileHeaderBase(LAST_VERSION), sectionNumber_(SECTION_SIZE) {}; 358 GetSectionNumber()359 const uint32_t &GetSectionNumber() const 360 { 361 return sectionNumber_; 362 } 363 364 private: 365 uint32_t sectionNumber_ {SECTION_SIZE}; 366 SectionInfo sectionInfos_; 367 }; 368 369 class PGOFileDataInterface { 370 public: 371 PGOFileDataInterface() = default; 372 virtual ~PGOFileDataInterface() = default; 373 virtual uint32_t ProcessToBinary(PGOContext &context, std::fstream &stream) = 0; 374 virtual uint32_t ParseFromBinary(PGOContext &context, void **buffer, PGOProfilerHeader const *header) = 0; 375 virtual bool ProcessToText(std::ofstream &stream) = 0; 376 // not support yet ParseFromText(std::ifstream & stream)377 virtual bool ParseFromText([[maybe_unused]] std::ifstream &stream) 378 { 379 return true; 380 }; 381 382 private: 383 NO_COPY_SEMANTIC(PGOFileDataInterface); 384 NO_MOVE_SEMANTIC(PGOFileDataInterface); 385 }; 386 387 class PGOFileSectionInterface : public PGOFileDataInterface { 388 public: 389 PGOFileSectionInterface() = default; 390 ~PGOFileSectionInterface() override = default; 391 virtual bool Support(PGOProfilerHeader const *header) const = 0; 392 virtual SectionInfo *GetSection(PGOProfilerHeader const *header) const = 0; 393 ParseSectionFromBinary(PGOContext & context,void * buffer,PGOProfilerHeader const * header,PGOFileSectionInterface & section)394 static bool ParseSectionFromBinary(PGOContext &context, void *buffer, PGOProfilerHeader const *header, 395 PGOFileSectionInterface §ion) 396 { 397 if (section.Support(header)) { 398 SectionInfo *info = section.GetSection(header); 399 if (info == nullptr) { 400 return false; 401 } 402 void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_); 403 section.ParseFromBinary(context, &addr, header); 404 } 405 return true; 406 } 407 ProcessSectionToBinary(PGOContext & context,std::fstream & fileStream,PGOProfilerHeader * const header,PGOFileSectionInterface & section)408 static bool ProcessSectionToBinary(PGOContext &context, std::fstream &fileStream, PGOProfilerHeader *const header, 409 PGOFileSectionInterface §ion) 410 { 411 auto *info = section.GetSection(header); 412 if (info == nullptr) { 413 return false; 414 } 415 info->offset_ = static_cast<uint32_t>(fileStream.tellp()); 416 info->number_ = section.ProcessToBinary(context, fileStream); 417 info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_; 418 return true; 419 } 420 421 private: 422 NO_COPY_SEMANTIC(PGOFileSectionInterface); 423 NO_MOVE_SEMANTIC(PGOFileSectionInterface); 424 }; 425 } // namespace panda::ecmascript::pgo 426 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_BASE_INFO_H