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