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 *>(&sectionInfos_) + 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 &section)377     static bool ParseSectionFromBinary(PGOContext &context, void *buffer, PGOProfilerHeader const *header,
378                                        PGOFileSectionInterface &section)
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 &section)391     static bool ProcessSectionToBinary(PGOContext &context, std::fstream &fileStream, PGOProfilerHeader *const header,
392                                        PGOFileSectionInterface &section)
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