• 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/global_index.h"
26 #include "ecmascript/js_hclass.h"
27 #include "ecmascript/log.h"
28 #include "ecmascript/log_wrapper.h"
29 #include "ecmascript/pgo_profiler/pgo_context.h"
30 #include "ecmascript/pgo_profiler/pgo_utils.h"
31 #include "ecmascript/on_heap.h"
32 #include "libpandabase/utils/bit_field.h"
33 #include "macros.h"
34 
35 namespace panda::ecmascript::pgo {
36 class ProfileTypeRef;
37 class PGOContext;
38 
39 using ApEntityId = pgo::ApEntityId;
40 
41 class ProfileType {
42 public:
43     enum class Kind : uint8_t {
44         ClassId,
45         ObjectLiteralId,
46         ArrayLiteralId,
47         BuiltinsId,
48         LegacyKind = BuiltinsId,
49         MethodId,           // method offset of js function
50         BuiltinFunctionId,  // function index of registered function
51         RecordClassId,
52         PrototypeId,
53         ConstructorId,
54         MegaStateKinds,
55         TotalKinds,
56         UnknowId,
57         GlobalsId,
58         JITClassId,
59         TransitionClassId,      // function class id after set prototype
60         TransitionPrototypeId   // function prototype id after set prototype
61     };
62 
63     static constexpr uint32_t RECORD_ID_FOR_BUNDLE = 1;
64 
65     static PUBLIC_API const ProfileType PROFILE_TYPE_NONE;
66 
67     static constexpr uint32_t ID_BITFIELD_NUM = 32;  // 0-31
68     static constexpr uint32_t ABC_ID_BITFIELD_NUM = 10; // 32-41
69     static constexpr uint32_t KIND_BITFIELD_NUM = 8;  // 42 - 49
70     using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>;
71     using AbcIdBits = IdBits::NextField<uint32_t, ABC_ID_BITFIELD_NUM>;
72     using KindBits = AbcIdBits::NextField<Kind, KIND_BITFIELD_NUM>;
73     using IsRootBits = KindBits::NextFlag;  // 50
74     using EverOutOfBoundsBits = IsRootBits::NextFlag; // 51
75 
76     using StringMap = std::multimap<std::string, std::string>;
77     using MapVector = std::vector<std::vector<StringMap>>;
78     using VariantVector = std::vector<std::variant<StringMap, MapVector, std::vector<StringMap>>>;
79     using VariantMap = std::multimap<std::string, std::variant<std::string, VariantVector>>;
80     using jModuleType = std::multimap<std::string, std::variant<std::string, std::vector<VariantMap>>>;
81 
82     class BuiltinsId {
83     public:
84         static constexpr uint32_t BUILTINS_ID_NUM = 16;
85         using BuiltinsIdBits = BitField<JSType, 0, BUILTINS_ID_NUM>;
86 
87         explicit BuiltinsId() = default;
BuiltinsId(uint32_t id)88         explicit BuiltinsId(uint32_t id) : id_(id) {}
89 
GetId()90         uint32_t GetId() const
91         {
92             return id_;
93         }
94 
SetBuiltinsId(JSType type)95         BuiltinsId SetBuiltinsId(JSType type)
96         {
97             id_ = BuiltinsIdBits::Update(id_, type);
98             return *this;
99         }
100 
GetBuiltinsId()101         JSType GetBuiltinsId() const
102         {
103             return BuiltinsIdBits::Decode(id_);
104         }
105 
GetIdToString()106         virtual std::string GetIdToString() const
107         {
108             std::stringstream ss;
109             ss << "(";
110             ss << GetId();
111             ss << ")";
112             return ss.str();
113         }
114 
115     protected:
116         uint32_t id_ { 0 };
117     };
118 
119     class BuiltinsArrayId : public BuiltinsId {
120     public:
121         // BuilitinsArray second bit field
122         static constexpr uint32_t OLD_ELEMENTS_KIND_BITFIELD_NUM = 5;
123         static constexpr uint32_t NEW_ELEMENTS_KIND_BITFIELD_NUM = 5;
124         using OldElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, OLD_ELEMENTS_KIND_BITFIELD_NUM>;
125         using NewElementsKindBits = OldElementsKindBits::NextField<ElementsKind, NEW_ELEMENTS_KIND_BITFIELD_NUM>;
126 
127         explicit BuiltinsArrayId() = default;
BuiltinsArrayId(uint32_t id)128         explicit BuiltinsArrayId(uint32_t id) : BuiltinsId(id) {}
129 
UpdateElementsKind(ElementsKind kind)130         BuiltinsArrayId UpdateElementsKind(ElementsKind kind)
131         {
132             id_ = OldElementsKindBits::Update(id_, kind);
133             return *this;
134         }
135 
GetElementsKind()136         ElementsKind GetElementsKind() const
137         {
138             return OldElementsKindBits::Decode(id_);
139         }
140 
UpdateTransitionElementsKind(ElementsKind kind)141         BuiltinsArrayId UpdateTransitionElementsKind(ElementsKind kind)
142         {
143             id_ = NewElementsKindBits::Update(id_, kind);
144             return *this;
145         }
146 
GetTransitionElementsKind()147         ElementsKind GetTransitionElementsKind() const
148         {
149             return NewElementsKindBits::Decode(id_);
150         }
151 
GetIdToString()152         std::string GetIdToString() const override
153         {
154             std::stringstream ss;
155             ss << "(";
156             ss << static_cast<uint32_t>(BuiltinsId::GetBuiltinsId()) << ", ";
157             ss << static_cast<uint32_t>(GetElementsKind()) << ", ";
158             ss << static_cast<uint32_t>(GetTransitionElementsKind());
159             ss << ")";
160             return ss.str();
161         }
162     };
163 
164     class BuiltinsTypedArrayId : public BuiltinsId {
165     public:
166         // BuilitinsTypedArray second bit field
167         static constexpr uint8_t ON_HEAP_MODE_BITFIELD_NUM = 2;
168         using OnHeapModeBits = BuiltinsArrayId::NewElementsKindBits::NextField<OnHeapMode, ON_HEAP_MODE_BITFIELD_NUM>;
169 
170         explicit BuiltinsTypedArrayId() = default;
BuiltinsTypedArrayId(uint32_t id)171         explicit BuiltinsTypedArrayId(uint32_t id) : BuiltinsId(id) {}
172 
UpdateOnHeapMode(OnHeapMode onHeapMode)173         BuiltinsTypedArrayId UpdateOnHeapMode(OnHeapMode onHeapMode)
174         {
175             id_ = OnHeapModeBits::Update(id_, onHeapMode);
176             return *this;
177         }
178 
GetOnHeapMode()179         OnHeapMode GetOnHeapMode() const
180         {
181             return OnHeapModeBits::Decode(id_);
182         }
183 
GetIdToString()184         std::string GetIdToString() const override
185         {
186             std::stringstream ss;
187             ss << "(";
188             ss << static_cast<uint32_t>(BuiltinsId::GetBuiltinsId()) << ", ";
189             auto builtinsArrayId = BuiltinsArrayId(GetId());
190             ss << static_cast<uint32_t>(builtinsArrayId.GetElementsKind()) << ", ";
191             ss << static_cast<uint32_t>(builtinsArrayId.GetTransitionElementsKind()) << ", ";
192             ss << static_cast<uint32_t>(GetOnHeapMode());
193             ss << ")";
194             return ss.str();
195         }
196     };
197 
198     static_assert(KindBits::IsValid(Kind::TotalKinds));
199 
200     ProfileType() = default;
ProfileType(uint64_t rawType)201     explicit ProfileType(uint64_t rawType) : type_(rawType) {};
202     ProfileType(PGOContext &context, ProfileTypeRef typeRef, bool *isValid = nullptr);
203     ProfileType(ApEntityId abcId, uint32_t type, Kind kind = Kind::ClassId, bool root = false,
204                 bool everOutOfBounds = false)
205     {
206         if (UNLIKELY(!IdBits::IsValid(type))) {
207             type_ = 0;
208         } else {
209             UpdateAbcId(abcId);
210             UpdateId(type);
211             UpdateKind(kind);
212             UpdateIsRootFlag(root);
213             UpdateEverOutOfBounds(everOutOfBounds);
214         }
215     }
216 
CreateMegaType()217     static ProfileType CreateMegaType()
218     {
219         ProfileType type;
220         type.UpdateKind(Kind::MegaStateKinds);
221         return type;
222     }
223 
CreateJITType()224     static ProfileType CreateJITType()
225     {
226         ProfileType type;
227         type.UpdateKind(Kind::JITClassId);
228         return type;
229     }
230 
CreateBuiltinsArray(ApEntityId abcId,JSType type,ElementsKind kind,ElementsKind transitionKind,bool everOutOfBounds)231     static ProfileType CreateBuiltinsArray(ApEntityId abcId, JSType type, ElementsKind kind,
232                                            ElementsKind transitionKind, bool everOutOfBounds)
233     {
234         auto id = BuiltinsArrayId().UpdateElementsKind(kind).UpdateTransitionElementsKind(transitionKind)
235                   .SetBuiltinsId(type).GetId();
236         return ProfileType(abcId, id, Kind::BuiltinsId, false, everOutOfBounds);
237     }
238 
CreateBuiltinsTypedArray(ApEntityId abcId,JSType type,OnHeapMode onHeap,bool everOutOfBounds)239     static ProfileType CreateBuiltinsTypedArray(ApEntityId abcId, JSType type, OnHeapMode onHeap,
240                                                 bool everOutOfBounds)
241     {
242         auto id = BuiltinsTypedArrayId().UpdateOnHeapMode(onHeap).SetBuiltinsId(type).GetId();
243         return ProfileType(abcId, id, Kind::BuiltinsId, false, everOutOfBounds);
244     }
245 
CreateBuiltins(ApEntityId abcId,JSType type)246     static ProfileType CreateBuiltins(ApEntityId abcId, JSType type)
247     {
248         auto id = BuiltinsId().SetBuiltinsId(type).GetId();
249         return ProfileType(abcId, id, Kind::BuiltinsId);
250     }
251 
CreateGlobals(ApEntityId abcId,GlobalIndex globalsId)252     static ProfileType CreateGlobals(ApEntityId abcId, GlobalIndex globalsId)
253     {
254         auto id = globalsId.GetGlobalIndex();
255         return ProfileType(abcId, id, Kind::GlobalsId);
256     }
257 
258     ProfileType &Remap(const PGOContext &context);
259 
IsNone()260     bool IsNone() const
261     {
262         return type_ == PROFILE_TYPE_NONE.type_;
263     }
264 
GetRaw()265     uint64_t GetRaw() const
266     {
267         return type_;
268     }
269 
IsRootType()270     bool IsRootType() const
271     {
272         return IsRootBits::Decode(type_);
273     }
274 
IsEverOutOfBounds()275     bool IsEverOutOfBounds() const
276     {
277         return EverOutOfBoundsBits::Decode(type_);
278     }
279 
IsGlobalsType()280     bool IsGlobalsType() const
281     {
282         return GetKind() == Kind::GlobalsId;
283     }
284 
IsBuiltinsType()285     bool IsBuiltinsType() const
286     {
287         return GetKind() == Kind::BuiltinsId;
288     }
289 
IsClassType()290     bool IsClassType() const
291     {
292         return GetKind() == Kind::ClassId;
293     }
294 
IsJITClassType()295     bool IsJITClassType() const
296     {
297         return GetKind() == Kind::JITClassId;
298     }
299 
IsMethodId()300     bool IsMethodId() const
301     {
302         return GetKind() == Kind::MethodId;
303     }
304 
IsBuiltinFunctionId()305     bool IsBuiltinFunctionId() const
306     {
307         return GetKind() == Kind::BuiltinFunctionId;
308     }
309 
IsArrayLiteralType()310     bool IsArrayLiteralType() const
311     {
312         return GetKind() == Kind::ArrayLiteralId;
313     }
314 
IsObjectLiteralType()315     bool IsObjectLiteralType() const
316     {
317         return GetKind() == Kind::ObjectLiteralId;
318     }
319 
IsConstructor()320     bool IsConstructor() const
321     {
322         return GetKind() == Kind::ConstructorId;
323     }
324 
IsPrototype()325     bool IsPrototype() const
326     {
327         return GetKind() == Kind::PrototypeId;
328     }
329 
IsTransitionClassType()330     bool IsTransitionClassType() const
331     {
332         return GetKind() == Kind::TransitionClassId;
333     }
334 
IsTransitionPrototype()335     bool IsTransitionPrototype() const
336     {
337         return GetKind() == Kind::TransitionPrototypeId;
338     }
339 
IsTransitionType()340     bool IsTransitionType() const
341     {
342         return IsTransitionClassType() || IsTransitionPrototype();
343     }
344 
IsMegaStateType()345     bool IsMegaStateType() const
346     {
347         return GetKind() == Kind::MegaStateKinds;
348     }
349 
IsGeneralizedClassType()350     bool IsGeneralizedClassType() const
351     {
352         return IsClassType() || IsTransitionClassType();
353     }
354 
IsGeneralizedPrototype()355     bool IsGeneralizedPrototype() const
356     {
357         return IsPrototype() || IsTransitionPrototype();
358     }
359 
GetId()360     uint32_t GetId() const
361     {
362         return IdBits::Decode(type_);
363     }
364 
GetKind()365     Kind GetKind() const
366     {
367         return KindBits::Decode(type_);
368     }
369 
GetAbcId()370     ApEntityId GetAbcId() const
371     {
372         return AbcIdBits::Decode(type_);
373     }
374 
UpdateAbcId(ApEntityId abcId)375     void UpdateAbcId(ApEntityId abcId)
376     {
377         type_ = AbcIdBits::Update(type_, abcId);
378     }
379 
380     bool operator<(const ProfileType &right) const
381     {
382         return type_ < right.type_;
383     }
384 
385     bool operator!=(const ProfileType &right) const
386     {
387         return type_ != right.type_;
388     }
389 
390     bool operator==(const ProfileType &right) const
391     {
392         return type_ == right.type_;
393     }
394 
GetTypeString()395     std::string GetTypeString() const
396     {
397         std::stringstream stream;
398         stream << "Type: " << "(isRoot: " << IsRootType() <<
399                 ", ever out of bounds: " << IsEverOutOfBounds() <<
400                 ", kind: " << std::showbase << std::dec << static_cast<uint32_t>(GetKind()) <<
401                 ", abcId: " << GetAbcId() << ", id: " << GetId() << ")";
402         return stream.str();
403     }
404 
GetTypeJson(StringMap & type)405     void GetTypeJson(StringMap &type) const
406     {
407         type.insert(std::make_pair(DumpJsonUtils::IS_ROOT, IsRootType() ? "true" : "false"));
408         type.insert(std::make_pair(DumpJsonUtils::KIND, std::to_string(static_cast<double>(GetKind()))));
409         type.insert(std::make_pair(DumpJsonUtils::ABC_ID, std::to_string(GetAbcId())));
410         std::string strId;
411         if (IsBuiltinsArray()) {
412             auto arrayId = BuiltinsArrayId(GetId());
413             strId = arrayId.GetIdToString();
414         } else if (IsBuiltinsTypeArray()) {
415             auto typedArrayId = BuiltinsTypedArrayId(GetId());
416             strId = typedArrayId.GetIdToString();
417         } else {
418             auto builtinsId = BuiltinsId(GetId());
419             strId = builtinsId.GetIdToString();
420         }
421         type.insert(std::make_pair(DumpJsonUtils::ID, strId));
422     }
423 
424     friend std::ostream& operator<<(std::ostream& os, const ProfileType& type)
425     {
426         os << type.GetTypeString();
427         return os;
428     }
429 
UpdateId(uint32_t id)430     void UpdateId(uint32_t id)
431     {
432         type_ = IdBits::Update(type_, id);
433     }
434 
UpdateKind(Kind kind)435     void UpdateKind(Kind kind)
436     {
437         type_ = KindBits::Update(type_, kind);
438     }
439 
UpdateIsRootFlag(bool root)440     void UpdateIsRootFlag(bool root)
441     {
442         type_ = IsRootBits::Update(type_, root);
443     }
444 
UpdateEverOutOfBounds(bool val)445     void UpdateEverOutOfBounds(bool val)
446     {
447         type_ = EverOutOfBoundsBits::Update(type_, val);
448     }
449 
IsValidCallMethodId()450     bool IsValidCallMethodId() const
451     {
452         return GetCallMethodId() > 0;
453     }
454 
IsValidClassConstructorMethodId()455     bool IsValidClassConstructorMethodId() const
456     {
457         return GetClassConstructorMethodId() > 0;
458     }
459 
GetCallMethodId()460     uint32_t GetCallMethodId() const
461     {
462         ASSERT(IsMethodId());
463         return GetId();
464     }
465 
GetClassConstructorMethodId()466     uint32_t GetClassConstructorMethodId() const
467     {
468         ASSERT(IsClassType());
469         return GetId();
470     }
471 
GetBuiltinsType()472     JSType GetBuiltinsType() const
473     {
474         ASSERT(IsBuiltinsType());
475         auto builtinsId = BuiltinsId(GetId());
476         return builtinsId.GetBuiltinsId();
477     }
478 
GetGlobalsId()479     GlobalIndex GetGlobalsId() const
480     {
481         ASSERT(IsGlobalsType());
482         auto globalsId = GlobalIndex(GetId());
483         return globalsId;
484     }
485 
GetElementsKindBeforeTransition()486     ElementsKind GetElementsKindBeforeTransition() const
487     {
488         ASSERT(IsBuiltinsArray());
489         auto builtinsArrayId = BuiltinsArrayId(GetId());
490         return builtinsArrayId.GetElementsKind();
491     }
492 
GetElementsKindAfterTransition()493     ElementsKind GetElementsKindAfterTransition() const
494     {
495         ASSERT(IsBuiltinsArray());
496         auto builtinsArrayId = BuiltinsArrayId(GetId());
497         return builtinsArrayId.GetTransitionElementsKind();
498     }
499 
IsBuiltinsMap()500     bool IsBuiltinsMap() const
501     {
502         if (IsBuiltinsType()) {
503             JSType type = GetBuiltinsType();
504             return type == JSType::JS_MAP;
505         }
506         return false;
507     }
508 
IsBuiltinsString()509     bool IsBuiltinsString() const
510     {
511         if (IsBuiltinsType()) {
512             JSType type = GetBuiltinsType();
513             return type >= JSType::STRING_FIRST && type <= JSType::STRING_LAST;
514         }
515         return false;
516     }
517 
IsBuiltinsArray()518     bool IsBuiltinsArray() const
519     {
520         if (IsBuiltinsType()) {
521             JSType type = GetBuiltinsType();
522             return type == JSType::JS_ARRAY;
523         }
524         return false;
525     }
526 
IsBuiltinsTypeArray()527     bool IsBuiltinsTypeArray() const
528     {
529         if (IsBuiltinsType()) {
530             JSType type = GetBuiltinsType();
531             return type > JSType::JS_TYPED_ARRAY_FIRST && type <= JSType::JS_TYPED_ARRAY_LAST;
532         }
533         return false;
534     }
535 
536 private:
UpdateId(uint64_t type)537     void UpdateId(uint64_t type)
538     {
539         type_ = IdBits::Update(type_, type);
540     }
541 
542     uint64_t type_ {0};
543 };
544 
545 struct HashProfileType {
operatorHashProfileType546     uint64_t operator()(const ProfileType &profileType) const
547     {
548         return profileType.GetRaw();
549     }
550 };
551 
552 class ProfileTypeRef {
553 public:
554     ProfileTypeRef() = default;
ProfileTypeRef(ApEntityId type)555     explicit ProfileTypeRef(ApEntityId type)
556     {
557         UpdateId(type);
558     }
559 
560     ProfileTypeRef(PGOContext &context, const ProfileType &type);
561 
562     ProfileTypeRef &Remap(const PGOContext &context);
563 
IsNone()564     bool IsNone() const
565     {
566         return typeId_ == 0;
567     }
568 
IsBuiltinsArray()569     bool IsBuiltinsArray() const
570     {
571         return false;
572     }
573 
IsConstructor()574     bool IsConstructor() const
575     {
576         return false;
577     }
578 
IsMegaStateType()579     bool IsMegaStateType() const
580     {
581         return false;
582     }
583 
GetId()584     ApEntityId GetId() const
585     {
586         return typeId_;
587     }
588 
589     bool operator<(const ProfileTypeRef &right) const
590     {
591         return typeId_ < right.typeId_;
592     }
593 
594     bool operator==(const ProfileTypeRef &right) const
595     {
596         return typeId_ == right.typeId_;
597     }
598 
GetTypeString()599     std::string GetTypeString() const
600     {
601         return std::to_string(typeId_);
602     }
603 
UpdateId(ApEntityId typeId)604     void UpdateId(ApEntityId typeId)
605     {
606         typeId_ = typeId;
607     }
608 
609 private:
610     ApEntityId typeId_ {0};
611 };
612 static_assert(sizeof(ProfileTypeRef) == sizeof(uint32_t));
613 
614 class ProfileTypeLegacy {
615 public:
616     static constexpr uint32_t ID_BITFIELD_NUM = 29;
617     static constexpr uint32_t KIND_BITFIELD_NUM = 3;
618     using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>;
619     using KindBits = IdBits::NextField<ProfileType::Kind, KIND_BITFIELD_NUM>;
620 
621     // legacy size check. for version lower than WIDE_CLASS_TYPE_MINI_VERSION, we should consider the legacy scenario.
622     static_assert(KindBits::IsValid(ProfileType::Kind::LegacyKind));
623 
624     explicit ProfileTypeLegacy(uint32_t type, ProfileType::Kind kind = ProfileType::Kind::ClassId)
625     {
626         if (!IdBits::IsValid(type)) {
627             type_ = 0;
628         } else {
629             UpdateId(type);
630             UpdateKind(kind);
631         }
632     }
633 
ProfileTypeLegacy(ProfileTypeRef profileTypeRef)634     explicit ProfileTypeLegacy(ProfileTypeRef profileTypeRef) : type_(profileTypeRef.GetId()) {}
635 
IsNone()636     bool IsNone() const
637     {
638         return type_ == 0;
639     }
640 
GetRaw()641     uint32_t GetRaw() const
642     {
643         return type_;
644     }
645 
GetId()646     uint32_t GetId() const
647     {
648         return IdBits::Decode(type_);
649     }
650 
GetKind()651     ProfileType::Kind GetKind() const
652     {
653         return KindBits::Decode(type_);
654     }
655 
656 private:
UpdateId(uint32_t type)657     void UpdateId(uint32_t type)
658     {
659         type_ = IdBits::Update(type_, type);
660     }
661 
UpdateKind(ProfileType::Kind kind)662     void UpdateKind(ProfileType::Kind kind)
663     {
664         type_ = KindBits::Update(type_, kind);
665     }
666     uint32_t type_ {0};
667 };
668 
669 class TraProfileType {
670 public:
TraProfileType(ProfileType root,ProfileType child)671     TraProfileType(ProfileType root, ProfileType child) : root_(root), child_(child) {}
672 
673 private:
674     ProfileType root_;
675     ProfileType child_;
676 };
677 } // namespace panda::ecmascript::pgo
678 #endif  // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILE_TYPE_H
679