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