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 FILE_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 117 static constexpr VersionType HEADER_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 118 static constexpr VersionType ELASTIC_HEADER_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION; 119 static constexpr VersionType LAST_VERSION = {0, 0, 0, 14}; 120 static constexpr size_t PANDA_FILE_SECTION_INDEX = 0; 121 static constexpr size_t RECORD_INFO_SECTION_INDEX = 1; 122 static constexpr size_t LAYOUT_DESC_SECTION_INDEX = 2; 123 static constexpr size_t RECORD_POOL_SECTION_INDEX = 3; 124 static constexpr size_t PROTO_TRANSITION_POOL_SECTION_INDEX = 4; 125 static constexpr size_t CLASS_TYPE_POOL_SECTION_INDEX = 5; 126 static constexpr size_t ABC_FILE_POOL_SECTION_INDEX = 6; 127 static constexpr size_t SECTION_SIZE = 7; 128 PGOProfilerHeader()129 PGOProfilerHeader() : base::FileHeaderElastic(LAST_VERSION), sectionNumber_(SECTION_SIZE) 130 { 131 GetPandaInfoSection()->offset_ = Size(); 132 SetHeaderSize(Size()); 133 } 134 LastSize()135 static size_t LastSize() 136 { 137 return sizeof(PGOProfilerHeader) + (SECTION_SIZE - 1) * sizeof(SectionInfo); 138 } 139 Size(uint32_t sectionNumber)140 static size_t Size(uint32_t sectionNumber) 141 { 142 ASSERT(sectionNumber > 0); 143 return sizeof(PGOProfilerHeader) + (sectionNumber - 1) * sizeof(SectionInfo); 144 } 145 Size() const146 size_t Size() const 147 { 148 return Size(sectionNumber_); 149 } 150 Verify() const151 bool Verify() const 152 { 153 return VerifyVersion("apPath file", LAST_VERSION, IsStrictMatch()); 154 } 155 Verify(void *buffer, size_t bufferSize) const156 bool Verify(void *buffer, size_t bufferSize) const 157 { 158 if (!Verify()) { 159 return false; 160 } 161 if (!VerifyConsistency(buffer, bufferSize)) { 162 return false; 163 } 164 if (!VerifyFileSize(bufferSize)) { 165 return false; 166 } 167 return true; 168 } 169 170 bool VerifyFileSize(size_t bufferSize) const; 171 172 bool VerifyConsistency(void *buffer, size_t bufferSize) const; 173 Build(PGOProfilerHeader **header, size_t size)174 static void Build(PGOProfilerHeader **header, size_t size) 175 { 176 void* rawMemory = malloc(size); 177 if (rawMemory == nullptr) { 178 LOG_ECMA(FATAL) << "Failed to apply for memory, size :" << size; 179 UNREACHABLE(); 180 } 181 *header = reinterpret_cast<PGOProfilerHeader *>(rawMemory); 182 new (*header) PGOProfilerHeader(); 183 } 184 Destroy(PGOProfilerHeader **header)185 static void Destroy(PGOProfilerHeader **header) 186 { 187 if (*header != nullptr) { 188 free(*header); 189 *header = nullptr; 190 } 191 } 192 193 // Copy Header. 194 static bool ParseFromBinary(void *buffer, size_t bufferSize, PGOProfilerHeader **header); 195 void ProcessToBinary(std::fstream &fileStream) const; 196 197 bool ParseFromText(std::ifstream &stream); 198 bool ProcessToText(std::ofstream &stream) const; 199 GetPandaInfoSection() const200 SectionInfo *GetPandaInfoSection() const 201 { 202 return GetSectionInfo(PANDA_FILE_SECTION_INDEX); 203 } 204 GetRecordInfoSection() const205 SectionInfo *GetRecordInfoSection() const 206 { 207 return GetSectionInfo(RECORD_INFO_SECTION_INDEX); 208 } 209 GetLayoutDescSection() const210 SectionInfo *GetLayoutDescSection() const 211 { 212 return GetSectionInfo(LAYOUT_DESC_SECTION_INDEX); 213 } 214 GetRecordPoolSection() const215 SectionInfo *GetRecordPoolSection() const 216 { 217 return GetSectionInfo(RECORD_POOL_SECTION_INDEX); 218 } 219 GetProfileTypeSection() const220 SectionInfo *GetProfileTypeSection() const 221 { 222 return GetSectionInfo(CLASS_TYPE_POOL_SECTION_INDEX); 223 } 224 GetAbcFilePoolSection() const225 SectionInfo *GetAbcFilePoolSection() const 226 { 227 return GetSectionInfo(ABC_FILE_POOL_SECTION_INDEX); 228 } 229 GetProtoTransitionPoolSection() const230 SectionInfo *GetProtoTransitionPoolSection() const 231 { 232 return GetSectionInfo(PROTO_TRANSITION_POOL_SECTION_INDEX); 233 } 234 SupportType() const235 bool SupportType() const 236 { 237 return CompatibleVerify(TYPE_MINI_VERSION); 238 } 239 SupportMethodChecksum() const240 bool SupportMethodChecksum() const 241 { 242 return CompatibleVerify(METHOD_CHECKSUM_MINI_VERSION); 243 } 244 SupportUseHClassType() const245 bool SupportUseHClassType() const 246 { 247 return CompatibleVerify(USE_HCLASS_TYPE_MINI_VERSION); 248 } 249 SupportProtoTransitionPool() const250 bool SupportProtoTransitionPool() const 251 { 252 return CompatibleVerify(PROTO_TRANSITION_POOL_MINI_VERSION); 253 } 254 SupportFileConsistency() const255 bool SupportFileConsistency() const 256 { 257 return CompatibleVerify(FILE_CONSISTENCY_MINI_VERSION); 258 } 259 SupportFileSize() const260 bool SupportFileSize() const 261 { 262 return CompatibleVerify(FILE_SIZE_MINI_VERSION); 263 } 264 SupportHeaderSize() const265 bool SupportHeaderSize() const 266 { 267 return CompatibleVerify(HEADER_SIZE_MINI_VERSION); 268 } 269 SupportTrackField() const270 bool SupportTrackField() const 271 { 272 return CompatibleVerify(TRACK_FIELD_MINI_VERSION); 273 } 274 SupportElementsKind() const275 bool SupportElementsKind() const 276 { 277 return CompatibleVerify(ELEMENTS_KIND_MINI_VERSION); 278 } 279 SupportRecordPool() const280 bool SupportRecordPool() const 281 { 282 return CompatibleVerify(RECORD_POOL_MINI_VERSION); 283 } 284 SupportWideProfileType() const285 bool SupportWideProfileType() const 286 { 287 return CompatibleVerify(WIDE_CLASS_TYPE_MINI_VERSION); 288 } 289 SupportProfileTypeWithAbcId() const290 bool SupportProfileTypeWithAbcId() const 291 { 292 return CompatibleVerify(PROFILE_TYPE_WITH_ABC_ID_MINI_VERSION); 293 } 294 SupportElementsTrackInfo() const295 bool SupportElementsTrackInfo() const 296 { 297 return CompatibleVerify(ELEMENTS_TRACK_INFO_MINI_VERSION); 298 } 299 IsCompatibleWithAOTFile() const300 bool IsCompatibleWithAOTFile() const 301 { 302 return VerifyVersion("ap file compatible aot file", GetCompatibleAnVersion(), AOTFileVersion::AN_VERSION, true); 303 } 304 IsStrictMatch()305 static bool IsStrictMatch() 306 { 307 return strictMatch_; 308 } 309 310 // just for test SetStrictMatch(bool strictMatch)311 static void SetStrictMatch(bool strictMatch) 312 { 313 strictMatch_ = strictMatch; 314 } 315 316 NO_COPY_SEMANTIC(PGOProfilerHeader); 317 NO_MOVE_SEMANTIC(PGOProfilerHeader); 318 319 private: 320 static bool BuildFromLegacy(void *buffer, PGOProfilerHeader **header); 321 static bool BuildFromElastic(void *buffer, size_t bufferSize, PGOProfilerHeader **header); 322 GetSectionInfo(size_t index) const323 SectionInfo *GetSectionInfo(size_t index) const 324 { 325 if (index >= sectionNumber_) { 326 return nullptr; 327 } 328 return const_cast<SectionInfo *>(§ionInfos_) + index; 329 } 330 331 uint32_t sectionNumber_ {SECTION_SIZE}; 332 SectionInfo sectionInfos_; 333 static bool strictMatch_; 334 }; 335 336 class PGOProfilerHeaderLegacy : public base::FileHeaderBase { 337 public: 338 static constexpr size_t SECTION_SIZE = 3; 339 static constexpr VersionType LAST_VERSION = {0, 0, 0, 5}; PGOProfilerHeaderLegacy()340 PGOProfilerHeaderLegacy() : base::FileHeaderBase(LAST_VERSION), sectionNumber_(SECTION_SIZE) {}; 341 GetSectionNumber() const342 const uint32_t &GetSectionNumber() const 343 { 344 return sectionNumber_; 345 } 346 347 private: 348 uint32_t sectionNumber_ {SECTION_SIZE}; 349 SectionInfo sectionInfos_; 350 }; 351 352 class PGOFileDataInterface { 353 public: 354 PGOFileDataInterface() = default; 355 virtual ~PGOFileDataInterface() = default; 356 virtual uint32_t ProcessToBinary(PGOContext &context, std::fstream &stream) = 0; 357 virtual uint32_t ParseFromBinary(PGOContext &context, void **buffer, PGOProfilerHeader const *header) = 0; 358 virtual bool ProcessToText(std::ofstream &stream) = 0; 359 // not support yet ParseFromText([[maybe_unused]] std::ifstream &stream)360 virtual bool ParseFromText([[maybe_unused]] std::ifstream &stream) 361 { 362 return true; 363 }; 364 365 private: 366 NO_COPY_SEMANTIC(PGOFileDataInterface); 367 NO_MOVE_SEMANTIC(PGOFileDataInterface); 368 }; 369 370 class PGOFileSectionInterface : public PGOFileDataInterface { 371 public: 372 PGOFileSectionInterface() = default; 373 ~PGOFileSectionInterface() override = default; 374 virtual bool Support(PGOProfilerHeader const *header) const = 0; 375 virtual SectionInfo *GetSection(PGOProfilerHeader const *header) const = 0; 376 ParseSectionFromBinary(PGOContext &context, void *buffer, PGOProfilerHeader const *header, PGOFileSectionInterface §ion)377 static bool ParseSectionFromBinary(PGOContext &context, void *buffer, PGOProfilerHeader const *header, 378 PGOFileSectionInterface §ion) 379 { 380 if (section.Support(header)) { 381 SectionInfo *info = section.GetSection(header); 382 if (info == nullptr) { 383 return false; 384 } 385 void *addr = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + info->offset_); 386 section.ParseFromBinary(context, &addr, header); 387 } 388 return true; 389 } 390 ProcessSectionToBinary(PGOContext &context, std::fstream &fileStream, PGOProfilerHeader *const header, PGOFileSectionInterface §ion)391 static bool ProcessSectionToBinary(PGOContext &context, std::fstream &fileStream, PGOProfilerHeader *const header, 392 PGOFileSectionInterface §ion) 393 { 394 auto *info = section.GetSection(header); 395 if (info == nullptr) { 396 return false; 397 } 398 info->offset_ = static_cast<uint32_t>(fileStream.tellp()); 399 info->number_ = section.ProcessToBinary(context, fileStream); 400 info->size_ = static_cast<uint32_t>(fileStream.tellp()) - info->offset_; 401 return true; 402 } 403 404 private: 405 NO_COPY_SEMANTIC(PGOFileSectionInterface); 406 NO_MOVE_SEMANTIC(PGOFileSectionInterface); 407 }; 408 } // namespace panda::ecmascript::pgo 409 #endif // ECMASCRIPT_PGO_PROFILER_AP_FILE_BASE_INFO_H