• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_TYPES_PGO_PROFILE_TYPE_H
17 #define ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILE_TYPE_H
18 
19 #include <cstdint>
20 #include <string>
21 #include <variant>
22 
23 #include "ecmascript/builtin_entries.h"
24 #include "ecmascript/elements.h"
25 #include "ecmascript/js_hclass.h"
26 #include "ecmascript/log.h"
27 #include "ecmascript/log_wrapper.h"
28 #include "ecmascript/pgo_profiler/pgo_context.h"
29 #include "ecmascript/pgo_profiler/pgo_utils.h"
30 #include "ecmascript/on_heap.h"
31 #include "libpandabase/utils/bit_field.h"
32 #include "macros.h"
33 
34 namespace panda::ecmascript::pgo {
35 class ProfileTypeRef;
36 class PGOContext;
37 
38 using ApEntityId = pgo::ApEntityId;
39 
40 class ProfileType {
41 public:
42     enum class Kind : uint8_t {
43         ClassId,
44         LiteralId,
45         BuiltinsId,
46         LegacyKind = BuiltinsId,
47         MethodId,           // method offset of js function
48         BuiltinFunctionId,  // function index of registered function
49         RecordClassId,
50         PrototypeId,
51         ConstructorId,
52         MegaStateKinds,
53         TotalKinds,
54         UnknowId
55     };
56 
57     static constexpr uint32_t RECORD_ID_FOR_BUNDLE = 1;
58 
59     static const ProfileType PROFILE_TYPE_NONE;
60 
61     static constexpr uint32_t ID_BITFIELD_NUM = 32;
62     static constexpr uint32_t ABC_ID_BITFIELD_NUM = 20;
63     static constexpr uint32_t KIND_BITFIELD_NUM = 11;
64     using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>;
65     using AbcIdBits = IdBits::NextField<uint32_t, ABC_ID_BITFIELD_NUM>;
66     using KindBits = AbcIdBits::NextField<Kind, KIND_BITFIELD_NUM>;
67     using IsRootBits = KindBits::NextFlag;
68 
69     class BuiltinsId {
70     public:
71         static constexpr uint32_t BUILTINS_ID_NUM = 16;
72         using BuiltinsIdBits = BitField<JSType, 0, BUILTINS_ID_NUM>;
73 
74         explicit BuiltinsId() = default;
BuiltinsId(uint32_t id)75         explicit BuiltinsId(uint32_t id) : id_(id) {}
76 
GetId()77         uint32_t GetId() const
78         {
79             return id_;
80         }
81 
SetBuiltinsId(JSType type)82         BuiltinsId SetBuiltinsId(JSType type)
83         {
84             id_ = BuiltinsIdBits::Update(id_, type);
85             return *this;
86         }
87 
GetBuiltinsId()88         JSType GetBuiltinsId() const
89         {
90             return BuiltinsIdBits::Decode(id_);
91         }
92 
93     protected:
94         uint32_t id_ { 0 };
95     };
96 
97     class BuiltinsArrayId : public BuiltinsId {
98     public:
99         // BuilitinsArray second bit field
100         static constexpr uint32_t OLD_ELEMENTS_KIND_BITFIELD_NUM = 5;
101         static constexpr uint32_t NEW_ELEMENTS_KIND_BITFIELD_NUM = 5;
102         using OldElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, OLD_ELEMENTS_KIND_BITFIELD_NUM>;
103         using NewElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, NEW_ELEMENTS_KIND_BITFIELD_NUM>;
104 
105         explicit BuiltinsArrayId() = default;
BuiltinsArrayId(uint32_t id)106         explicit BuiltinsArrayId(uint32_t id) : BuiltinsId(id) {}
107 
UpdateElementsKind(ElementsKind kind)108         BuiltinsArrayId UpdateElementsKind(ElementsKind kind)
109         {
110             id_ = OldElementsKindBits::Update(id_, kind);
111             return *this;
112         }
113 
GetElementsKind()114         ElementsKind GetElementsKind() const
115         {
116             return OldElementsKindBits::Decode(id_);
117         }
118 
UpdateTransitionElementsKind(ElementsKind kind)119         BuiltinsArrayId UpdateTransitionElementsKind(ElementsKind kind)
120         {
121             id_ = NewElementsKindBits::Update(id_, kind);
122             return *this;
123         }
124 
GetTransitionElementsKind()125         ElementsKind GetTransitionElementsKind() const
126         {
127             return NewElementsKindBits::Decode(id_);
128         }
129     };
130 
131     class BuiltinsTypedArrayId : public BuiltinsId {
132     public:
133         // BuilitinsTypedArray second bit field
134         static constexpr uint8_t ON_HEAP_MODE_BITFIELD_NUM = 2;
135         using OnHeapModeBits = BuiltinsIdBits::NextField<OnHeapMode, ON_HEAP_MODE_BITFIELD_NUM>;
136 
137         explicit BuiltinsTypedArrayId() = default;
BuiltinsTypedArrayId(uint32_t id)138         explicit BuiltinsTypedArrayId(uint32_t id) : BuiltinsId(id) {}
139 
UpdateOnHeapMode(OnHeapMode onHeapMode)140         BuiltinsTypedArrayId UpdateOnHeapMode(OnHeapMode onHeapMode)
141         {
142             id_ = OnHeapModeBits::Update(id_, onHeapMode);
143             return *this;
144         }
145 
GetOnHeapMode()146         OnHeapMode GetOnHeapMode() const
147         {
148             return OnHeapModeBits::Decode(id_);
149         }
150     };
151 
152     static_assert(KindBits::IsValid(Kind::TotalKinds));
153 
154     ProfileType() = default;
ProfileType(uint64_t rawType)155     explicit ProfileType(uint64_t rawType) : type_(rawType) {};
156     ProfileType(PGOContext &context, ProfileTypeRef typeRef);
157     ProfileType(ApEntityId abcId, uint32_t type, Kind kind = Kind::ClassId, bool root = false)
158     {
159         if (UNLIKELY(!IdBits::IsValid(type))) {
160             type_ = 0;
161         } else {
162             UpdateAbcId(abcId);
163             UpdateId(type);
164             UpdateKind(kind);
165             UpdateIsRootFlag(root);
166         }
167     }
168 
CreateMegeType()169     static ProfileType CreateMegeType()
170     {
171         ProfileType type;
172         type.UpdateKind(Kind::MegaStateKinds);
173         return type;
174     }
175 
CreateBuiltinsArray(ApEntityId abcId,JSType type,ElementsKind kind,ElementsKind transitionKind)176     static ProfileType CreateBuiltinsArray(ApEntityId abcId, JSType type, ElementsKind kind,
177                                            ElementsKind transitionKind)
178     {
179         auto id = BuiltinsArrayId().UpdateElementsKind(kind).UpdateTransitionElementsKind(transitionKind)
180                   .SetBuiltinsId(type).GetId();
181         return ProfileType(abcId, id, Kind::BuiltinsId);
182     }
183 
CreateBuiltinsTypedArray(ApEntityId abcId,JSType type,OnHeapMode onHeap)184     static ProfileType CreateBuiltinsTypedArray(ApEntityId abcId, JSType type, OnHeapMode onHeap)
185     {
186         auto id = BuiltinsTypedArrayId().UpdateOnHeapMode(onHeap).SetBuiltinsId(type).GetId();
187         return ProfileType(abcId, id, Kind::BuiltinsId);
188     }
189 
CreateBuiltins(ApEntityId abcId,JSType type)190     static ProfileType CreateBuiltins(ApEntityId abcId, JSType type)
191     {
192         auto id = BuiltinsId().SetBuiltinsId(type).GetId();
193         return ProfileType(abcId, id, Kind::BuiltinsId);
194     }
195 
196     ProfileType &Remap(const PGOContext &context);
197 
IsNone()198     bool IsNone() const
199     {
200         return type_ == PROFILE_TYPE_NONE.type_;
201     }
202 
GetRaw()203     uint64_t GetRaw() const
204     {
205         return type_;
206     }
207 
IsRootType()208     bool IsRootType() const
209     {
210         return IsRootBits::Decode(type_);
211     }
212 
IsBuiltinsType()213     bool IsBuiltinsType() const
214     {
215         return GetKind() == Kind::BuiltinsId;
216     }
217 
IsClassType()218     bool IsClassType() const
219     {
220         return GetKind() == Kind::ClassId;
221     }
222 
IsMethodId()223     bool IsMethodId() const
224     {
225         return GetKind() == Kind::MethodId;
226     }
227 
IsBuiltinFunctionId()228     bool IsBuiltinFunctionId() const
229     {
230         return GetKind() == Kind::BuiltinFunctionId;
231     }
232 
IsLiteralType()233     bool IsLiteralType() const
234     {
235         return GetKind() == Kind::LiteralId;
236     }
237 
IsConstructor()238     bool IsConstructor() const
239     {
240         return GetKind() == Kind::ConstructorId;
241     }
242 
IsPrototype()243     bool IsPrototype() const
244     {
245         return GetKind() == Kind::PrototypeId;
246     }
247 
IsMegaStateType()248     bool IsMegaStateType() const
249     {
250         return GetKind() == Kind::MegaStateKinds;
251     }
252 
GetId()253     uint32_t GetId() const
254     {
255         return IdBits::Decode(type_);
256     }
257 
GetKind()258     Kind GetKind() const
259     {
260         return KindBits::Decode(type_);
261     }
262 
GetAbcId()263     ApEntityId GetAbcId() const
264     {
265         return AbcIdBits::Decode(type_);
266     }
267 
UpdateAbcId(ApEntityId abcId)268     void UpdateAbcId(ApEntityId abcId)
269     {
270         type_ = AbcIdBits::Update(type_, abcId);
271     }
272 
273     bool operator<(const ProfileType &right) const
274     {
275         return type_ < right.type_;
276     }
277 
278     bool operator!=(const ProfileType &right) const
279     {
280         return type_ != right.type_;
281     }
282 
283     bool operator==(const ProfileType &right) const
284     {
285         return type_ == right.type_;
286     }
287 
GetTypeString()288     std::string GetTypeString() const
289     {
290         std::stringstream stream;
291         stream << "Type: " << "(isRoot: " << IsRootType() <<
292                 ", kind: " << std::showbase << std::dec << static_cast<uint32_t>(GetKind()) <<
293                 ", abcId: " << GetAbcId() <<
294                 ", id: " << GetId() << ")";
295         return stream.str();
296     }
297 
UpdateId(uint32_t id)298     void UpdateId(uint32_t id)
299     {
300         type_ = IdBits::Update(type_, id);
301     }
302 
UpdateKind(Kind kind)303     void UpdateKind(Kind kind)
304     {
305         type_ = KindBits::Update(type_, kind);
306     }
307 
UpdateIsRootFlag(bool root)308     void UpdateIsRootFlag(bool root)
309     {
310         type_ = IsRootBits::Update(type_, root);
311     }
312 
IsValidCallMethodId()313     bool IsValidCallMethodId() const
314     {
315         return GetCallMethodId() > 0;
316     }
317 
GetCallMethodId()318     uint32_t GetCallMethodId() const
319     {
320         ASSERT(IsMethodId());
321         return GetId();
322     }
323 
GetBuiltinsId()324     JSType GetBuiltinsId() const
325     {
326         ASSERT(IsBuiltinsType());
327         auto builtinsId = BuiltinsId(GetId());
328         return builtinsId.GetBuiltinsId();
329     }
330 
GetElementsKind()331     ElementsKind GetElementsKind() const
332     {
333         ASSERT(IsBuiltinsArray());
334         auto builtinsArrayId = BuiltinsArrayId(GetId());
335         return builtinsArrayId.GetElementsKind();
336     }
337 
IsBuiltinsString()338     bool IsBuiltinsString() const
339     {
340         if (IsBuiltinsType()) {
341             JSType type = GetBuiltinsId();
342             return type >= JSType::STRING_FIRST && type <= JSType::STRING_LAST;
343         }
344         return false;
345     }
346 
IsBuiltinsArray()347     bool IsBuiltinsArray() const
348     {
349         if (IsBuiltinsType()) {
350             JSType type = GetBuiltinsId();
351             return type == JSType::JS_ARRAY;
352         }
353         return false;
354     }
355 
IsBuiltinsTypeArray()356     bool IsBuiltinsTypeArray() const
357     {
358         if (IsBuiltinsType()) {
359             JSType type = GetBuiltinsId();
360             return type > JSType::JS_TYPED_ARRAY_FIRST && type <= JSType::JS_TYPED_ARRAY_LAST;
361         }
362         return false;
363     }
364 
365 private:
UpdateId(uint64_t type)366     void UpdateId(uint64_t type)
367     {
368         type_ = IdBits::Update(type_, type);
369     }
370 
371     uint64_t type_ {0};
372 };
373 
374 struct HashProfileType {
operatorHashProfileType375     uint64_t operator()(const ProfileType &profileType) const
376     {
377         return profileType.GetRaw();
378     }
379 };
380 
381 class ProfileTypeRef {
382 public:
383     ProfileTypeRef() = default;
ProfileTypeRef(ApEntityId type)384     explicit ProfileTypeRef(ApEntityId type)
385     {
386         UpdateId(type);
387     }
388 
389     ProfileTypeRef(PGOContext &context, const ProfileType &type);
390 
391     ProfileTypeRef &Remap(const PGOContext &context);
392 
IsNone()393     bool IsNone() const
394     {
395         return typeId_ == 0;
396     }
397 
IsBuiltinsArray()398     bool IsBuiltinsArray() const
399     {
400         return false;
401     }
402 
IsConstructor()403     bool IsConstructor() const
404     {
405         return false;
406     }
407 
IsMegaStateType()408     bool IsMegaStateType() const
409     {
410         return false;
411     }
412 
GetId()413     ApEntityId GetId() const
414     {
415         return typeId_;
416     }
417 
418     bool operator<(const ProfileTypeRef &right) const
419     {
420         return typeId_ < right.typeId_;
421     }
422 
423     bool operator==(const ProfileTypeRef &right) const
424     {
425         return typeId_ == right.typeId_;
426     }
427 
GetTypeString()428     std::string GetTypeString() const
429     {
430         return std::to_string(typeId_);
431     }
432 
UpdateId(ApEntityId typeId)433     void UpdateId(ApEntityId typeId)
434     {
435         typeId_ = typeId;
436     }
437 
438 private:
439     ApEntityId typeId_ {0};
440 };
441 static_assert(sizeof(ProfileTypeRef) == sizeof(uint32_t));
442 
443 class ProfileTypeLegacy {
444 public:
445     static constexpr uint32_t ID_BITFIELD_NUM = 29;
446     static constexpr uint32_t KIND_BITFIELD_NUM = 3;
447     using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>;
448     using KindBits = IdBits::NextField<ProfileType::Kind, KIND_BITFIELD_NUM>;
449 
450     // legacy size check. for version lower than WIDE_CLASS_TYPE_MINI_VERSION, we should consider the legacy scenario.
451     static_assert(KindBits::IsValid(ProfileType::Kind::LegacyKind));
452 
453     explicit ProfileTypeLegacy(uint32_t type, ProfileType::Kind kind = ProfileType::Kind::ClassId)
454     {
455         if (!IdBits::IsValid(type)) {
456             type_ = 0;
457         } else {
458             UpdateId(type);
459             UpdateKind(kind);
460         }
461     }
462 
ProfileTypeLegacy(ProfileTypeRef profileTypeRef)463     explicit ProfileTypeLegacy(ProfileTypeRef profileTypeRef) : type_(profileTypeRef.GetId()) {}
464 
IsNone()465     bool IsNone() const
466     {
467         return type_ == 0;
468     }
469 
GetRaw()470     uint32_t GetRaw() const
471     {
472         return type_;
473     }
474 
GetId()475     uint32_t GetId() const
476     {
477         return IdBits::Decode(type_);
478     }
479 
GetKind()480     ProfileType::Kind GetKind() const
481     {
482         return KindBits::Decode(type_);
483     }
484 
485 private:
UpdateId(uint32_t type)486     void UpdateId(uint32_t type)
487     {
488         type_ = IdBits::Update(type_, type);
489     }
490 
UpdateKind(ProfileType::Kind kind)491     void UpdateKind(ProfileType::Kind kind)
492     {
493         type_ = KindBits::Update(type_, kind);
494     }
495     uint32_t type_ {0};
496 };
497 
498 class TraProfileType {
499 public:
TraProfileType(ProfileType root,ProfileType child)500     TraProfileType(ProfileType root, ProfileType child) : root_(root), child_(child) {}
501 
502 private:
503     ProfileType root_;
504     ProfileType child_;
505 };
506 } // namespace panda::ecmascript::pgo
507 #endif  // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILE_TYPE_H
508