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