• 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_PROFILER_TYPE_H
17 #define ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILER_TYPE_H
18 
19 #include <stdint.h>
20 #include <string>
21 #include <variant>
22 #include <vector>
23 
24 #include "ecmascript/elements.h"
25 #include "ecmascript/js_hclass.h"
26 #include "ecmascript/mem/region.h"
27 #include "ecmascript/log_wrapper.h"
28 #include "ecmascript/pgo_profiler/pgo_utils.h"
29 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
30 #include "libpandabase/utils/bit_field.h"
31 #include "macros.h"
32 
33 namespace panda::ecmascript::pgo {
34 class PGOContext;
35 class PGOType {
36 public:
37     enum class TypeKind : uint8_t {
38         SCALAR_OP_TYPE,
39         RW_OP_TYPE,
40         DEFINE_OP_TYPE,
41         PROTO_TRANSITION_TYPE,
42     };
43     PGOType() = default;
PGOType(TypeKind kind)44     explicit PGOType(TypeKind kind) : kind_(kind) {}
45 
IsScalarOpType()46     bool IsScalarOpType() const
47     {
48         return kind_ == TypeKind::SCALAR_OP_TYPE;
49     }
50 
IsRwOpType()51     bool IsRwOpType() const
52     {
53         return kind_ == TypeKind::RW_OP_TYPE;
54     }
55 
IsDefineOpType()56     bool IsDefineOpType() const
57     {
58         return kind_ == TypeKind::DEFINE_OP_TYPE;
59     }
60 
IsProtoTransitionType()61     bool IsProtoTransitionType() const
62     {
63         return kind_ == TypeKind::PROTO_TRANSITION_TYPE;
64     }
65 
66 private:
67     TypeKind kind_ {TypeKind::SCALAR_OP_TYPE};
68 };
69 
70 /**
71  * | INT    \          -> INT_OVERFLOW \
72  * |           NUMBER                    NUMBER_HETEROE1
73  * | DOUBLE /                          /
74  */
75 template <typename PGOProfileType>
76 class PGOSampleTemplate : public PGOType {
77 public:
78     static constexpr int WEIGHT_BITS = 11;
79     static constexpr int WEIGHT_START_BIT = 10;
80     static constexpr int WEIGHT_TRUE_START_BIT = WEIGHT_START_BIT + WEIGHT_BITS;
81     static constexpr int WEIGHT_MASK = (1 << WEIGHT_BITS) - 1;
82     static constexpr int WEIGHT_THRESHOLD = WEIGHT_MASK; // 2047
83 
84     enum class Type : uint32_t {
85         NONE = 0x0ULL,
86         INT = 0x1ULL,                        // 00000001
87         INT_OVERFLOW = (0x1ULL << 1) | INT,  // 00000011
88         DOUBLE = 0x1ULL << 2,                // 00000100
89         NUMBER = INT | DOUBLE,               // 00000101
90         NUMBER1 = INT_OVERFLOW | DOUBLE,     // 00000111
91         BOOLEAN = 0x1ULL << 3,
92         UNDEFINED_OR_NULL = 0x1ULL << 4,
93         SPECIAL = 0x1ULL << 5,
94         BOOLEAN_OR_SPECIAL = BOOLEAN | SPECIAL,
95         STRING = 0x1ULL << 6,
96         NUMBER_OR_STRING = NUMBER | STRING,
97         BIG_INT = 0x1ULL << 7,
98         HEAP_OBJECT = 0x1ULL << 8,
99         HEAP_OR_UNDEFINED_OR_NULL = HEAP_OBJECT | UNDEFINED_OR_NULL,
100         ANY = (0x1ULL << WEIGHT_START_BIT) - 1,
101     };
102 
PGOSampleTemplate()103     PGOSampleTemplate() : type_(Type::NONE) {};
104 
PGOSampleTemplate(Type type)105     explicit PGOSampleTemplate(Type type) : type_(type) {};
PGOSampleTemplate(uint32_t type)106     explicit PGOSampleTemplate(uint32_t type) : type_(Type(type)) {};
PGOSampleTemplate(PGOProfileType type)107     explicit PGOSampleTemplate(PGOProfileType type) : type_(type) {}
108 
109     template <typename FromType>
ConvertFrom(PGOContext & context,const FromType & from)110     static PGOSampleTemplate ConvertFrom(PGOContext &context, const FromType &from)
111     {
112         if (from.IsProfileType()) {
113             return PGOSampleTemplate(PGOProfileType(context, from.GetProfileType()));
114         }
115         return PGOSampleTemplate(static_cast<PGOSampleTemplate::Type>(from.GetType()));
116     }
117 
118     static PGOSampleTemplate CreateProfileType(ApEntityId recordId, int32_t profileType,
119                                                typename ProfileType::Kind kind = ProfileType::Kind::ClassId,
120                                                bool isRoot = false)
121     {
122         return PGOSampleTemplate(PGOProfileType(recordId, profileType, kind, isRoot));
123     }
124 
NoneType()125     static PGOSampleTemplate NoneType()
126     {
127         return PGOSampleTemplate(Type::NONE);
128     }
129 
None()130     static int32_t None()
131     {
132         return static_cast<int32_t>(Type::NONE);
133     }
134 
AnyType()135     static int32_t AnyType()
136     {
137         return static_cast<int32_t>(Type::ANY);
138     }
139 
IntType()140     static int32_t IntType()
141     {
142         return static_cast<int32_t>(Type::INT);
143     }
144 
IntOverFlowType()145     static int32_t IntOverFlowType()
146     {
147         return static_cast<int32_t>(Type::INT_OVERFLOW);
148     }
149 
DoubleType()150     static int32_t DoubleType()
151     {
152         return static_cast<int32_t>(Type::DOUBLE);
153     }
154 
NumberType()155     static int32_t NumberType()
156     {
157         return static_cast<int32_t>(Type::NUMBER);
158     }
159 
HeapObjectType()160     static int32_t HeapObjectType()
161     {
162         return static_cast<int32_t>(Type::HEAP_OBJECT);
163     }
164 
UndefineOrNullType()165     static int32_t UndefineOrNullType()
166     {
167         return static_cast<int32_t>(Type::UNDEFINED_OR_NULL);
168     }
169 
BooleanType()170     static int32_t BooleanType()
171     {
172         return static_cast<int32_t>(Type::BOOLEAN);
173     }
174 
StringType()175     static int32_t StringType()
176     {
177         return static_cast<int32_t>(Type::STRING);
178     }
179 
NumberOrStringType()180     static int32_t NumberOrStringType()
181     {
182         return static_cast<int32_t>(Type::NUMBER_OR_STRING);
183     }
184 
BigIntType()185     static int32_t BigIntType()
186     {
187         return static_cast<int32_t>(Type::BIG_INT);
188     }
189 
SpecialType()190     static int32_t SpecialType()
191     {
192         return static_cast<int32_t>(Type::SPECIAL);
193     }
194 
CombineType(int32_t curType,int32_t newType)195     static int32_t CombineType(int32_t curType, int32_t newType)
196     {
197         return static_cast<int32_t>(static_cast<uint32_t>(curType) | static_cast<uint32_t>(newType));
198     }
199 
NoneProfileType()200     static PGOSampleTemplate NoneProfileType()
201     {
202         return PGOSampleTemplate(PGOProfileType());
203     }
204 
CombineType(PGOSampleTemplate type)205     PGOSampleTemplate CombineType(PGOSampleTemplate type)
206     {
207         if (IsPrimitiveType()) {
208             if (std::holds_alternative<PGOProfileType>(type.type_)) {
209                 LOG_ECMA(ERROR) << "The type is PGOProfileType, but need a Type";
210                 return *this;
211             }
212             auto oldType = static_cast<uint32_t>(std::get<Type>(type_));
213             oldType = oldType & static_cast<uint32_t>(AnyType());
214             type_ =
215                 Type(oldType | static_cast<uint32_t>(std::get<Type>(type.type_)));
216         } else {
217             this->SetType(type);
218         }
219         return *this;
220     }
221 
CombineCallTargetType(PGOSampleTemplate type)222     PGOSampleTemplate CombineCallTargetType(PGOSampleTemplate type)
223     {
224         ASSERT(type_.index() == 1);
225         ProfileType::Kind oldKind = GetProfileType().GetKind();
226         ProfileType::Kind newKind = type.GetProfileType().GetKind();
227         uint32_t oldMethodId = GetProfileType().GetId();
228         uint32_t newMethodId = type.GetProfileType().GetId();
229         // If we have recorded a valid method if before, invalidate it.
230         if ((oldMethodId != 0) &&
231             ((oldKind != newKind) || (oldMethodId != newMethodId))) {
232             type_ = ProfileType::PROFILE_TYPE_NONE;
233         }
234         return *this;
235     }
236 
SetType(PGOSampleTemplate type)237     void SetType(PGOSampleTemplate type)
238     {
239         type_ = type.type_;
240     }
241 
GetTypeString()242     std::string GetTypeString() const
243     {
244         if (IsPrimitiveType()) {
245             return std::to_string(static_cast<uint32_t>(std::get<Type>(type_)));
246         } else {
247             return std::get<PGOProfileType>(type_).GetTypeString();
248         }
249     }
250 
GetTypeJson(ProfileType::StringMap & type)251     void GetTypeJson(ProfileType::StringMap &type) const
252     {
253         if (IsPrimitiveType()) {
254             type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME,
255                 std::to_string(static_cast<uint32_t>(std::get<Type>(type_)))));
256         } else {
257             type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, "Type"));
258             std::get<PGOProfileType>(type_).GetTypeJson(type);
259         }
260         if (IsScalarOpType()) {
261             if (!ToString().empty()) {
262                 type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, ToString()));
263             }
264         }
265     }
266 
ToString()267     std::string ToString() const
268     {
269         if (IsPrimitiveType()) {
270             auto type = std::get<Type>(type_);
271             switch (type) {
272                 case Type::NONE:
273                     return "none";
274                 case Type::INT:
275                     return "int";
276                 case Type::INT_OVERFLOW:
277                     return "int_overflow";
278                 case Type::DOUBLE:
279                     return "double";
280                 case Type::NUMBER:
281                     return "number";
282                 case Type::NUMBER1:
283                     return "number1";
284                 case Type::BOOLEAN:
285                     return "boolean";
286                 case Type::UNDEFINED_OR_NULL:
287                     return "undefined_or_null";
288                 case Type::SPECIAL:
289                     return "special";
290                 case Type::BOOLEAN_OR_SPECIAL:
291                     return "boolean_or_special";
292                 case Type::STRING:
293                     return "string";
294                 case Type::BIG_INT:
295                     return "big_int";
296                 case Type::HEAP_OBJECT:
297                     return "heap_object";
298                 case Type::HEAP_OR_UNDEFINED_OR_NULL:
299                     return "heap_or_undefined_or_null";
300                 case Type::ANY:
301                     return "any";
302                 default:
303                     return "";
304             }
305         }
306         return "";
307     }
308 
IsProfileType()309     bool IsProfileType() const
310     {
311         return type_.index() == 1;
312     }
313 
GetProfileType()314     PGOProfileType GetProfileType() const
315     {
316         ASSERT(IsProfileType());
317         return std::get<PGOProfileType>(type_);
318     }
319 
IsPrimitiveType()320     bool IsPrimitiveType() const
321     {
322         return type_.index() == 0;
323     }
324 
GetPrimitiveType()325     Type GetPrimitiveType() const
326     {
327         ASSERT(IsPrimitiveType());
328         auto type = static_cast<uint32_t>(std::get<Type>(type_));
329         return Type(type & static_cast<uint32_t>(AnyType()));
330     }
331 
GetWeight()332     uint32_t GetWeight() const
333     {
334         ASSERT(IsPrimitiveType());
335         auto type = static_cast<uint32_t>(std::get<Type>(type_));
336         return type >> WEIGHT_START_BIT;
337     }
338 
IsAny()339     bool IsAny() const
340     {
341         return IsPrimitiveType() && GetPrimitiveType() == Type::ANY;
342     }
343 
IsNone()344     bool IsNone() const
345     {
346         return IsPrimitiveType() && GetPrimitiveType() == Type::NONE;
347     }
348 
IsInt()349     bool IsInt() const
350     {
351         return IsPrimitiveType() && GetPrimitiveType() == Type::INT;
352     }
353 
IsIntOverFlow()354     bool IsIntOverFlow() const
355     {
356         return IsPrimitiveType() && GetPrimitiveType() == Type::INT_OVERFLOW;
357     }
358 
IsDouble()359     bool IsDouble() const
360     {
361         return IsPrimitiveType() && GetPrimitiveType() == Type::DOUBLE;
362     }
363 
IsString()364     bool IsString() const
365     {
366         return IsPrimitiveType() && GetPrimitiveType() == Type::STRING;
367     }
368 
IsBigInt()369     bool IsBigInt() const
370     {
371         return type_.index() == 0 && GetPrimitiveType() == Type::BIG_INT;
372     }
373 
IsBoolean()374     bool IsBoolean() const
375     {
376         return type_.index() == 0 && GetPrimitiveType() == Type::BOOLEAN;
377     }
378 
IsHeapObject()379     bool IsHeapObject() const
380     {
381         return type_.index() == 0 && GetPrimitiveType() == Type::HEAP_OBJECT;
382     }
383 
IsNumber()384     bool IsNumber() const
385     {
386         if (type_.index() != 0) {
387             return false;
388         }
389         auto primType = GetPrimitiveType();
390         return primType == Type::NUMBER || primType == Type::NUMBER1;
391     }
392 
IsNumberOrString()393     bool IsNumberOrString() const
394     {
395         if (type_.index() != 0) {
396             return false;
397         }
398         auto primType = GetPrimitiveType();
399         return primType == Type::NUMBER_OR_STRING;
400     }
401 
HasNumber()402     bool HasNumber() const
403     {
404         if (type_.index() != 0) {
405             return false;
406         }
407         auto primType = GetPrimitiveType();
408         switch (primType) {
409             case Type::INT:
410             case Type::INT_OVERFLOW:
411             case Type::DOUBLE:
412             case Type::NUMBER:
413             case Type::NUMBER1:
414                 return true;
415             default:
416                 return false;
417         }
418     }
419 
IsProfileTypeNone()420     bool IsProfileTypeNone() const
421     {
422         return type_.index() == 1 && GetProfileType() == ProfileType::PROFILE_TYPE_NONE;
423     }
424 
425     bool operator<(const PGOSampleTemplate &right) const
426     {
427         return type_ < right.type_;
428     }
429 
430     bool operator!=(const PGOSampleTemplate &right) const
431     {
432         return type_ != right.type_;
433     }
434 
435     bool operator==(const PGOSampleTemplate &right) const
436     {
437         return type_ == right.type_;
438     }
439 
GetType()440     Type GetType() const
441     {
442         ASSERT(!IsProfileType());
443         return std::get<Type>(type_);
444     }
445 
446 private:
447     std::variant<Type, PGOProfileType> type_;
448 };
449 
450 using PGOSampleType = PGOSampleTemplate<ProfileType>;
451 using PGOSampleTypeRef = PGOSampleTemplate<ProfileTypeRef>;
452 
453 template <typename PGOProfileType>
454 class PGOProtoChainTemplate {
455 public:
456     static constexpr int32_t PROTO_CHAIN_MIN_COUNT = 0;
457     static constexpr int32_t PROTO_CHAIN_MAX_COUNT = 4096;
458 
459     PGOProtoChainTemplate() = default;
PGOProtoChainTemplate(int32_t size,int32_t count)460     PGOProtoChainTemplate(int32_t size, int32_t count) : size_(size), count_(count) {};
461 
CreateProtoChain(std::vector<std::pair<PGOProfileType,PGOProfileType>> protoChain)462     static PGOProtoChainTemplate *CreateProtoChain(std::vector<std::pair<PGOProfileType, PGOProfileType>> protoChain)
463     {
464         auto count = protoChain.size();
465         size_t size = sizeof(PGOProtoChainTemplate);
466         if (count != 0) {
467             size += sizeof(PGOProfileType) * (count - 1) * 2;   // 2 means mul by 2
468         }
469         auto result = reinterpret_cast<PGOProtoChainTemplate *>(malloc(size));
470         if (result == nullptr) {
471             LOG_ECMA_MEM(FATAL) << "malloc failed";
472             UNREACHABLE();
473         }
474         new (result) PGOProtoChainTemplate(size, count);
475         PGOProfileType *curPt = &(result->rootType_);
476         for (auto iter : protoChain) {
477             *curPt = iter.first;
478             curPt = curPt + 1;
479             *curPt = iter.second;
480             curPt = curPt + 1;
481         }
482         return result;
483     }
484 
DeleteProtoChain(PGOProtoChainTemplate * protoChain)485     static void DeleteProtoChain(PGOProtoChainTemplate *protoChain)
486     {
487         free(protoChain);
488     }
489 
490     template <typename FromType>
ConvertFrom(PGOContext & context,FromType * from)491     static PGOProtoChainTemplate *ConvertFrom(PGOContext &context, FromType *from)
492     {
493         auto count = from->GetCount();
494         size_t size = sizeof(PGOProtoChainTemplate);
495         if (count != 0) {
496             size += sizeof(PGOProfileType) * (static_cast<size_t>(count) - 1) * 2;   // 2 means mul by 2
497         }
498         auto result = reinterpret_cast<PGOProtoChainTemplate *>(malloc(size));
499         if (result == nullptr) {
500             LOG_ECMA_MEM(FATAL) << "malloc failed";
501             UNREACHABLE();
502         }
503         new (result) PGOProtoChainTemplate(size, count);
504         PGOProfileType *curPt = &(result->rootType_);
505         from->IterateProtoChain([&context, &curPt] (auto rootType, auto childType) {
506             *curPt = PGOProfileType(context, rootType);
507             curPt = curPt + 1;
508             *curPt = PGOProfileType(context, childType);
509             curPt = curPt + 1;
510         });
511         return result;
512     }
513 
514     template <typename Callback>
IterateProtoChain(Callback callback)515     void IterateProtoChain(Callback callback) const
516     {
517         if (count_ < PROTO_CHAIN_MIN_COUNT || count_ > PROTO_CHAIN_MAX_COUNT) {
518             return;
519         }
520         for (int i = 0; i < count_; i++) {
521             callback(*(&rootType_ + i), *(&rootType_ + i + 1));
522         }
523     }
524 
GetCount()525     int32_t GetCount()
526     {
527         return count_;
528     }
529 
Size()530     int32_t Size()
531     {
532         return size_;
533     }
534 
535 private:
536     int32_t size_;
537     int32_t count_;
538     PGOProfileType rootType_ {PGOProfileType()};
539     PGOProfileType childType_ {PGOProfileType()};
540 };
541 
542 using PGOProtoChain = PGOProtoChainTemplate<ProfileType>;
543 using PGOProtoChainRef = PGOProtoChainTemplate<ProfileTypeRef>;
544 
545 enum class ProtoChainMarker : uint8_t {
546     EXSIT,
547     NOT_EXSIT,
548 };
549 
550 template <typename PGOProfileType, typename PGOSampleType>
551 class PGOObjectTemplate {
552 public:
553     PGOObjectTemplate() = default;
PGOObjectTemplate(PGOProfileType type)554     PGOObjectTemplate(PGOProfileType type) : receiverType_(type) {}
PGOObjectTemplate(PGOProfileType receiverType,JSHClass * receiver,JSHClass * hold,JSHClass * holdTra,PGOSampleType accessorMethod)555     PGOObjectTemplate(PGOProfileType receiverType, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra,
556                       PGOSampleType accessorMethod)
557         : receiverType_(receiverType), receiver_(receiver), holder_(hold), holdTra_(holdTra),
558           accessorMethod_(accessorMethod) {}
PGOObjectTemplate(PGOProfileType receiverRootType,PGOProfileType receiverType,PGOProfileType holdRootType,PGOProfileType holdType,PGOProfileType holdTraRootType,PGOProfileType holdTraType,PGOSampleType accessorMethod)559     PGOObjectTemplate(PGOProfileType receiverRootType,
560                       PGOProfileType receiverType, PGOProfileType holdRootType,
561                       PGOProfileType holdType, PGOProfileType holdTraRootType,
562                       PGOProfileType holdTraType, PGOSampleType accessorMethod)
563         : receiverRootType_(receiverRootType), receiverType_(receiverType),
564           holdRootType_(holdRootType), holdType_(holdType),
565           holdTraRootType_(holdTraRootType), holdTraType_(holdTraType),
566           accessorMethod_(accessorMethod) {}
567 
AddPrototypePt(std::vector<std::pair<PGOProfileType,PGOProfileType>> protoChain)568     void AddPrototypePt(std::vector<std::pair<PGOProfileType, PGOProfileType>> protoChain)
569     {
570         protoChainMarker_ = ProtoChainMarker::EXSIT;
571         if (protoChain_ != nullptr) {
572             PGOProtoChainTemplate<PGOProfileType>::DeleteProtoChain(protoChain_);
573         }
574         protoChain_ = PGOProtoChainTemplate<PGOProfileType>::CreateProtoChain(protoChain);
575     }
576 
577     template <typename FromType>
ConvertFrom(PGOContext & context,const FromType & from)578     void ConvertFrom(PGOContext &context, const FromType &from)
579     {
580         receiverRootType_ = PGOProfileType(context, from.GetReceiverRootType());
581         receiverType_ = PGOProfileType(context, from.GetReceiverType());
582         holdRootType_ = PGOProfileType(context, from.GetHoldRootType());
583         holdType_ = PGOProfileType(context, from.GetHoldType());
584         holdTraRootType_ = PGOProfileType(context, from.GetHoldTraRootType());
585         holdTraType_ = PGOProfileType(context, from.GetHoldTraType());
586         accessorMethod_ = PGOSampleType::ConvertFrom(context, from.GetAccessorMethod());
587         protoChainMarker_ = from.GetProtoChainMarker();
588     }
589 
GetInfoString()590     std::string GetInfoString() const
591     {
592         std::string result = "(receiverRoot";
593         result += receiverRootType_.GetTypeString();
594         result += ", receiver";
595         result += receiverType_.GetTypeString();
596         result += ", holdRoot";
597         result += holdRootType_.GetTypeString();
598         result += ", hold";
599         result += holdType_.GetTypeString();
600         result += ", holdTraRoot";
601         result += holdTraRootType_.GetTypeString();
602         result += ", holdTra";
603         result += holdTraType_.GetTypeString();
604         result += ", accessorMethod";
605         result += accessorMethod_.GetTypeString();
606         result += ")";
607         return result;
608     }
609 
610     template <typename T>
AddTypeJson(const char * typeName,const T & type,std::string typeOffset,std::vector<ProfileType::StringMap> & typeArray)611     void AddTypeJson(const char *typeName, const T& type, std::string typeOffset,
612                      std::vector<ProfileType::StringMap> &typeArray) const
613     {
614         ProfileType::StringMap typeJson;
615         typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeName));
616         typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_OFFSET, typeOffset));
617         type.GetTypeJson(typeJson);
618         typeArray.push_back(typeJson);
619     }
620 
GetInfoJson(std::vector<ProfileType::StringMap> & typeArray,std::string typeoffset)621     void GetInfoJson(std::vector<ProfileType::StringMap> &typeArray, std::string typeoffset) const
622     {
623         AddTypeJson("receiverRootType", receiverRootType_, typeoffset, typeArray);
624         AddTypeJson("receiverType", receiverType_, typeoffset, typeArray);
625         AddTypeJson("holdRootType", holdRootType_, typeoffset, typeArray);
626         AddTypeJson("holdType", holdType_, typeoffset, typeArray);
627         AddTypeJson("holdTraRootType", holdTraRootType_, typeoffset, typeArray);
628         AddTypeJson("holdTraType", holdTraType_, typeoffset, typeArray);
629         AddTypeJson("accessorMethodType", accessorMethod_, typeoffset, typeArray);
630     }
631 
GetProfileType()632     PGOProfileType GetProfileType() const
633     {
634         return receiverType_;
635     }
636 
GetReceiverRootType()637     PGOProfileType GetReceiverRootType() const
638     {
639         return receiverRootType_;
640     }
641 
GetReceiverType()642     PGOProfileType GetReceiverType() const
643     {
644         return receiverType_;
645     }
646 
GetHoldRootType()647     PGOProfileType GetHoldRootType() const
648     {
649         return holdRootType_;
650     }
651 
GetHoldType()652     PGOProfileType GetHoldType() const
653     {
654         return holdType_;
655     }
656 
GetHoldTraRootType()657     PGOProfileType GetHoldTraRootType() const
658     {
659         return holdTraRootType_;
660     }
661 
GetHoldTraType()662     PGOProfileType GetHoldTraType() const
663     {
664         return holdTraType_;
665     }
666 
GetAccessorMethod()667     PGOSampleType GetAccessorMethod() const
668     {
669         return accessorMethod_;
670     }
671 
GetProtoChainMarker()672     ProtoChainMarker GetProtoChainMarker() const
673     {
674         return protoChainMarker_;
675     }
676 
GetProtoChain()677     PGOProtoChainTemplate<PGOProfileType> *GetProtoChain() const
678     {
679         return protoChain_;
680     }
681 
SetProtoChain(PGOProtoChainTemplate<PGOProfileType> * protoChain)682     void SetProtoChain(PGOProtoChainTemplate<PGOProfileType> *protoChain)
683     {
684         protoChain_ = protoChain;
685     }
686 
IsNone()687     bool IsNone() const
688     {
689         return receiverType_.IsNone();
690     }
691 
IsMegaStateType()692     bool IsMegaStateType() const
693     {
694         return receiverType_.IsMegaStateType();
695     }
696 
IsJITClassType()697     bool IsJITClassType() const
698     {
699         return receiverType_.IsJITClassType();
700     }
701 
InConstructor()702     bool InConstructor() const
703     {
704         return receiverType_.IsConstructor();
705     }
706 
InElement()707     bool InElement() const
708     {
709         return receiverType_.IsBuiltinsArray();
710     }
711 
712     bool operator<(const PGOObjectTemplate &right) const
713     {
714         if (receiverRootType_ != right.receiverRootType_) {
715             return receiverRootType_ < right.receiverRootType_;
716         }
717         if (receiverType_ != right.receiverType_) {
718             return receiverType_ < right.receiverType_;
719         }
720         if (holdRootType_ != right.holdRootType_) {
721             return holdRootType_ < right.holdRootType_;
722         }
723         if (holdType_ != right.holdType_) {
724             return holdType_ < right.holdType_;
725         }
726         if (holdTraRootType_ != right.holdTraRootType_) {
727             return holdTraRootType_ < right.holdTraRootType_;
728         }
729         return holdTraType_ < right.holdTraType_;
730     }
731 
732     bool operator==(const PGOObjectTemplate &right) const
733     {
734         return receiverRootType_ == right.receiverRootType_ && receiverType_ == right.receiverType_ &&
735             holdRootType_ == right.holdRootType_ && holdType_ == right.holdType_ &&
736             holdTraRootType_ == right.holdTraRootType_ && holdTraType_ == right.holdTraType_ &&
737             receiver_ == right.receiver_ && holder_ == right.holder_ && holdTra_ == right.holdTra_;
738     }
739 
740     // Only Use For JIT
GetReceiverHclass()741     JSHClass* GetReceiverHclass() const
742     {
743         ASSERT(receiverType_.IsJITClassType());
744         return receiver_;
745     }
GetHolderHclass()746     JSHClass* GetHolderHclass() const
747     {
748         ASSERT(receiverType_.IsJITClassType());
749         return holder_;
750     }
GetHolderTraHclass()751     JSHClass* GetHolderTraHclass() const
752     {
753         ASSERT(receiverType_.IsJITClassType());
754         return holdTra_;
755     }
756 
757 private:
758     PGOProfileType receiverRootType_ { PGOProfileType() };
759     PGOProfileType receiverType_ { PGOProfileType() };
760     PGOProfileType holdRootType_ { PGOProfileType() };
761     PGOProfileType holdType_ { PGOProfileType() };
762     PGOProfileType holdTraRootType_ { PGOProfileType() };
763     PGOProfileType holdTraType_ { PGOProfileType() };
764     JSHClass* receiver_  {nullptr};
765     JSHClass* holder_ {nullptr};
766     JSHClass *holdTra_ {nullptr};
767     PGOSampleType accessorMethod_ { PGOSampleType() };
768     ProtoChainMarker protoChainMarker_ {ProtoChainMarker::NOT_EXSIT};
769     PGOProtoChainTemplate<PGOProfileType> *protoChain_ { nullptr };
770 };
771 using PGOObjectInfo = PGOObjectTemplate<ProfileType, PGOSampleType>;
772 using PGOObjectInfoRef = PGOObjectTemplate<ProfileTypeRef, PGOSampleTypeRef>;
773 
774 template <typename PGOObjectInfoType>
775 class PGORWOpTemplate : public PGOType {
776 public:
PGORWOpTemplate()777     PGORWOpTemplate() : PGOType(TypeKind::RW_OP_TYPE) {};
778 
779     template <typename FromType>
ConvertFrom(PGOContext & context,const FromType & from)780     void ConvertFrom(PGOContext &context, const FromType &from)
781     {
782         count_ = std::min(from.GetCount(), static_cast<uint32_t>(POLY_CASE_NUM));
783         for (uint32_t index = 0; index < count_; index++) {
784             infos_[index].ConvertFrom(context, from.GetObjectInfo(index));
785         }
786     }
787 
Merge(const PGORWOpTemplate & type)788     void Merge(const PGORWOpTemplate &type)
789     {
790         for (uint32_t i = 0; i < type.count_; i++) {
791             AddObjectInfo(type.infos_[i]);
792         }
793     }
794 
AddObjectInfo(const PGOObjectInfoType & info)795     void AddObjectInfo(const PGOObjectInfoType &info)
796     {
797         if (info.IsNone()) {
798             return;
799         }
800         if (info.IsMegaStateType()) {
801             count_ = 1;
802             infos_[0] = info;
803             return;
804         }
805         uint32_t count = 0;
806         for (; count < count_; count++) {
807             if (infos_[count] == info) {
808                 return;
809             }
810         }
811         if (count < static_cast<uint32_t>(POLY_CASE_NUM)) {
812             infos_[count] = info;
813             count_++;
814         } else {
815             LOG_ECMA(DEBUG) << "Class type exceeds 4, discard";
816         }
817     }
818 
GetObjectInfo(uint32_t index)819     const PGOObjectInfoType &GetObjectInfo(uint32_t index) const
820     {
821         ASSERT(index < count_);
822         return infos_[index];
823     }
824 
GetCount()825     uint32_t GetCount() const
826     {
827         return count_;
828     }
829 
830 private:
831     static constexpr int POLY_CASE_NUM = 4;
832     uint32_t count_ = 0;
833     PGOObjectInfoType infos_[POLY_CASE_NUM];
834 };
835 using PGORWOpType = PGORWOpTemplate<PGOObjectInfo>;
836 using PGORWOpTypeRef = PGORWOpTemplate<PGOObjectInfoRef>;
837 
838 template <typename PGOProfileType>
839 class PGODefineOpTemplate : public PGOType {
840 public:
PGODefineOpTemplate()841     PGODefineOpTemplate() : PGOType(TypeKind::DEFINE_OP_TYPE), type_(PGOProfileType()) {};
PGODefineOpTemplate(PGOProfileType type)842     explicit PGODefineOpTemplate(PGOProfileType type) : PGOType(TypeKind::DEFINE_OP_TYPE), type_(type) {};
PGODefineOpTemplate(PGOProfileType type,JSHClass * hclass)843     explicit PGODefineOpTemplate(PGOProfileType type, JSHClass* hclass) : PGOType(TypeKind::DEFINE_OP_TYPE),
844                                                                           type_(type), receiver_(hclass) {};
845 
846     template <typename FromType>
ConvertFrom(PGOContext & context,const FromType & from)847     void ConvertFrom(PGOContext &context, const FromType &from)
848     {
849         type_ = PGOProfileType(context, from.GetProfileType());
850         ctorPt_ = PGOProfileType(context, from.GetCtorPt());
851         protoPt_ = PGOProfileType(context, from.GetProtoTypePt());
852         kind_ = from.GetElementsKind();
853         elementsLength_ = from.GetElementsLength();
854         spaceFlag_ = from.GetSpaceFlag();
855     }
856 
GetTypeString()857     std::string GetTypeString() const
858     {
859         std::string result = "(local";
860         result += type_.GetTypeString();
861         result += ", ctor";
862         result += ctorPt_.GetTypeString();
863         result += ", proto";
864         result += protoPt_.GetTypeString();
865         result += ", elementsKind:";
866         result += std::to_string(static_cast<int32_t>(kind_));
867         if (elementsLength_ > 0 && spaceFlag_ != RegionSpaceFlag::UNINITIALIZED) {
868             result += ", size: ";
869             result += std::to_string(elementsLength_);
870             result += ", space; ";
871             result += ToSpaceTypeName(spaceFlag_);
872         }
873         return result;
874     }
875 
876     template <typename T>
AddTypeJson(const char * typeName,const T & type,std::string typeOffset,std::vector<ProfileType::StringMap> & sameOffsetTypeArray)877     void AddTypeJson(const char *typeName, const T& type, std::string typeOffset,
878                      std::vector<ProfileType::StringMap> &sameOffsetTypeArray) const
879     {
880         ProfileType::StringMap typeJson;
881         typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeName));
882         typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeOffset));
883         type.GetTypeJson(typeJson);
884         sameOffsetTypeArray.push_back(typeJson);
885     }
886 
GetTypeJson(std::vector<ProfileType::StringMap> & sameOffsetTypeArray,std::string typeOffset)887     void GetTypeJson(std::vector<ProfileType::StringMap> &sameOffsetTypeArray,
888                      std::string typeOffset) const
889     {
890         AddTypeJson("localType", type_, typeOffset, sameOffsetTypeArray);
891         AddTypeJson("ctorType", ctorPt_, typeOffset, sameOffsetTypeArray);
892         AddTypeJson("protoType", protoPt_, typeOffset, sameOffsetTypeArray);
893     }
894 
IsNone()895     bool IsNone() const
896     {
897         return type_.IsNone();
898     }
899 
GetProfileType()900     PGOProfileType GetProfileType() const
901     {
902         return type_;
903     }
904 
SetCtorPt(PGOProfileType type)905     void SetCtorPt(PGOProfileType type)
906     {
907         ctorPt_ = type;
908     }
909 
GetCtorPt()910     PGOProfileType GetCtorPt() const
911     {
912         return ctorPt_;
913     }
914 
SetProtoTypePt(PGOProfileType type)915     void SetProtoTypePt(PGOProfileType type)
916     {
917         protoPt_ = type;
918     }
919 
GetProtoTypePt()920     PGOProfileType GetProtoTypePt() const
921     {
922         return protoPt_;
923     }
924 
SetElementsKind(ElementsKind kind)925     void SetElementsKind(ElementsKind kind)
926     {
927         kind_ = kind;
928     }
929 
GetElementsKind()930     ElementsKind GetElementsKind() const
931     {
932         return kind_;
933     }
934 
SetElementsLength(uint32_t length)935     void SetElementsLength(uint32_t length)
936     {
937         elementsLength_ = length;
938     }
939 
GetElementsLength()940     uint32_t GetElementsLength() const
941     {
942         return elementsLength_;
943     }
944 
SetSpaceFlag(RegionSpaceFlag flag)945     void SetSpaceFlag(RegionSpaceFlag flag)
946     {
947         spaceFlag_ = flag;
948     }
949 
GetSpaceFlag()950     RegionSpaceFlag GetSpaceFlag() const
951     {
952         return spaceFlag_;
953     }
954 
955     bool operator<(const PGODefineOpTemplate &right) const
956     {
957         return this->GetProfileType() < right.GetProfileType();
958     }
959 
GetReceiver()960     JSHClass* GetReceiver() const
961     {
962         ASSERT(type_.IsJITClassType());
963         return receiver_;
964     }
965 
966 private:
967     PGOProfileType type_ { PGOProfileType() };
968     PGOProfileType ctorPt_ { PGOProfileType() };
969     PGOProfileType protoPt_ { PGOProfileType() };
970     uint32_t elementsLength_ { 0 };
971     ElementsKind kind_ { ElementsKind::NONE };
972     RegionSpaceFlag spaceFlag_  { RegionSpaceFlag::UNINITIALIZED };
973     JSHClass* receiver_ {nullptr};
974 };
975 
976 using PGODefineOpType = PGODefineOpTemplate<ProfileType>;
977 using PGODefineOpTypeRef = PGODefineOpTemplate<ProfileTypeRef>;
978 
979 template <typename PGOProfileType>
980 class PGOProtoTransitionTemplate : public PGOType {
981 public:
PGOProtoTransitionTemplate()982     PGOProtoTransitionTemplate() : PGOType(TypeKind::PROTO_TRANSITION_TYPE), ihcType_(PGOProfileType()) {};
PGOProtoTransitionTemplate(PGOProfileType type)983     explicit PGOProtoTransitionTemplate(PGOProfileType type) : PGOType(TypeKind::PROTO_TRANSITION_TYPE),
984                                                                ihcType_(type) {}
985 
986     template <typename FromType>
ConvertFrom(PGOContext & context,const FromType & from)987     void ConvertFrom(PGOContext &context, const FromType &from)
988     {
989         ihcType_ = PGOProfileType(context, from.GetIhcType());
990         baseRootPt_ = PGOProfileType(context, from.GetBaseType().first);
991         basePt_ = PGOProfileType(context, from.GetBaseType().second);
992         transIhcType_ = PGOProfileType(context, from.GetTransitionType());
993         transProtoPt_ = PGOProfileType(context, from.GetTransitionProtoPt());
994     }
995 
GetTypeString()996     std::string GetTypeString() const
997     {
998         std::string result = "(ihc";
999         result += ihcType_.GetTypeString();
1000         result += ", baseRoot";
1001         result += baseRootPt_.GetTypeString();
1002         result += ", base";
1003         result += basePt_.GetTypeString();
1004         result += ", transIhc";
1005         result += transIhcType_.GetTypeString();
1006         result += ", transProto";
1007         result += transProtoPt_.GetTypeString();
1008         result += ")";
1009         return result;
1010     }
1011 
IsNone()1012     bool IsNone() const
1013     {
1014         return ihcType_.IsNone() || transIhcType_.IsNone();
1015     }
1016 
IsProtoTransitionNone()1017     bool IsProtoTransitionNone() const
1018     {
1019         return transIhcType_.IsNone();
1020     }
1021 
GetIhcType()1022     PGOProfileType GetIhcType() const
1023     {
1024         return ihcType_;
1025     }
1026 
SetBaseType(PGOProfileType rootType,PGOProfileType type)1027     void SetBaseType(PGOProfileType rootType, PGOProfileType type)
1028     {
1029         baseRootPt_ = rootType;
1030         basePt_ = type;
1031     }
1032 
GetBaseType()1033     std::pair<PGOProfileType, PGOProfileType> GetBaseType() const
1034     {
1035         return std::make_pair(baseRootPt_, basePt_);
1036     }
1037 
SetTransitionType(PGOProfileType type)1038     void SetTransitionType(PGOProfileType type)
1039     {
1040         transIhcType_ = type;
1041     }
1042 
GetTransitionType()1043     PGOProfileType GetTransitionType() const
1044     {
1045         return transIhcType_;
1046     }
1047 
SetTransitionProtoPt(PGOProfileType type)1048     void SetTransitionProtoPt(PGOProfileType type)
1049     {
1050         transProtoPt_ = type;
1051     }
1052 
GetTransitionProtoPt()1053     PGOProfileType GetTransitionProtoPt() const
1054     {
1055         return transProtoPt_;
1056     }
1057 
1058     bool operator<(const PGOProtoTransitionTemplate &right) const
1059     {
1060         return this->GetIhcType() < right.GetIhcType();
1061     }
1062 
IsSameProtoTransition(const PGOProtoTransitionTemplate & type)1063     bool IsSameProtoTransition(const PGOProtoTransitionTemplate &type) const
1064     {
1065         return (GetBaseType().first == type.GetBaseType().first) &&
1066                (GetBaseType().second == type.GetBaseType().second) &&
1067                (GetTransitionType() == type.GetTransitionType()) &&
1068                (GetTransitionProtoPt() == type.GetTransitionProtoPt());
1069     }
1070 
1071     // only support mono-state prototype transition now
CombineType(const PGOProtoTransitionTemplate & type)1072     PGOProtoTransitionTemplate CombineType(const PGOProtoTransitionTemplate &type)
1073     {
1074         ASSERT(GetIhcType() == type.GetIhcType());
1075         if (IsProtoTransitionNone() || IsSameProtoTransition(type)) {
1076             return *this;
1077         }
1078         // clear all except for key
1079         SetBaseType(PGOProfileType(), PGOProfileType());
1080         SetTransitionType(PGOProfileType());
1081         SetTransitionProtoPt(PGOProfileType());
1082         return *this;
1083     }
1084 
1085 private:
1086     PGOProfileType ihcType_ { PGOProfileType() };  // key
1087     PGOProfileType baseRootPt_ { PGOProfileType() };
1088     PGOProfileType basePt_ { PGOProfileType() };
1089     PGOProfileType transIhcType_ { PGOProfileType() };
1090     PGOProfileType transProtoPt_ { PGOProfileType() };
1091 };
1092 using PGOProtoTransitionType = PGOProtoTransitionTemplate<ProfileType>;
1093 using PGOProtoTransitionTypeRef = PGOProtoTransitionTemplate<ProfileTypeRef>;
1094 
1095 class PGOTypeRef {
1096 public:
PGOTypeRef()1097     PGOTypeRef() : type_(nullptr) {}
1098 
PGOTypeRef(PGOType * type)1099     explicit PGOTypeRef(PGOType *type) : type_(type) {}
1100 
PGOTypeRef(const PGOSampleType * type)1101     explicit PGOTypeRef(const PGOSampleType *type) : type_(static_cast<const PGOType*>(type)) {}
1102 
PGOTypeRef(const PGORWOpType * type)1103     explicit PGOTypeRef(const PGORWOpType *type) : type_(static_cast<const PGOType*>(type)) {}
1104 
PGOTypeRef(const PGODefineOpType * type)1105     explicit PGOTypeRef(const PGODefineOpType *type) : type_(static_cast<const PGOType*>(type)) {}
1106 
PGOTypeRef(const PGOProtoTransitionType * type)1107     explicit PGOTypeRef(const PGOProtoTransitionType *type) : type_(static_cast<const PGOType*>(type)) {}
1108 
NoneType()1109     static PGOTypeRef NoneType()
1110     {
1111         return PGOTypeRef();
1112     }
1113 
1114     bool operator<(const PGOTypeRef &right) const
1115     {
1116         return type_ < right.type_;
1117     }
1118 
1119     bool operator!=(const PGOTypeRef &right) const
1120     {
1121         return type_ != right.type_;
1122     }
1123 
1124     bool operator==(const PGOTypeRef &right) const
1125     {
1126         return type_ == right.type_;
1127     }
1128 
IsValid()1129     bool IsValid() const
1130     {
1131         return type_ != nullptr;
1132     }
1133 
IsValidCallMethodId()1134     bool IsValidCallMethodId() const
1135     {
1136         if (type_ == nullptr) {
1137             return false;
1138         }
1139         if (!type_->IsScalarOpType()) {
1140             return false;
1141         }
1142         auto sampleType = static_cast<const PGOSampleType*>(type_);
1143         if (sampleType->IsProfileType()) {
1144             if (sampleType->GetProfileType().IsMethodId()) {
1145                 return sampleType->GetProfileType().IsValidCallMethodId();
1146             }
1147             if (sampleType->GetProfileType().IsClassType()) {
1148                 return sampleType->GetProfileType().IsValidClassConstructorMethodId();
1149             }
1150         }
1151         return false;
1152     }
1153 
IsDefOpValidCallMethodId()1154     bool IsDefOpValidCallMethodId() const
1155     {
1156         if (type_ == nullptr) {
1157             return false;
1158         }
1159         if (!type_->IsDefineOpType()) {
1160             return false;
1161         }
1162         auto sampleType = static_cast<const PGODefineOpType*>(type_);
1163         if (sampleType->GetProfileType().IsMethodId()) {
1164             return sampleType->GetProfileType().IsValidCallMethodId();
1165         }
1166         if (sampleType->GetProfileType().IsClassType()) {
1167             return sampleType->GetProfileType().IsValidClassConstructorMethodId();
1168         }
1169         return false;
1170     }
1171 
GetCallMethodId()1172     uint32_t GetCallMethodId() const
1173     {
1174         auto sampleType = static_cast<const PGOSampleType*>(type_);
1175         if (sampleType->GetProfileType().IsClassType()) {
1176             return sampleType->GetProfileType().GetClassConstructorMethodId();
1177         }
1178         return sampleType->GetProfileType().GetCallMethodId();
1179     }
1180 
GetDefOpCallMethodId()1181     uint32_t GetDefOpCallMethodId() const
1182     {
1183         auto sampleType = static_cast<const PGODefineOpType*>(type_);
1184         if (sampleType->GetProfileType().IsClassType()) {
1185             return sampleType->GetProfileType().GetClassConstructorMethodId();
1186         }
1187         return sampleType->GetProfileType().GetCallMethodId();
1188     }
1189 
GetValue()1190     uint64_t GetValue() const
1191     {
1192         auto sampleType = static_cast<const PGOSampleType*>(type_);
1193         return sampleType->GetProfileType().GetRaw();
1194     }
1195 
GetPGOSampleType()1196     const PGOSampleType* GetPGOSampleType() const
1197     {
1198         if (type_ == nullptr) {
1199             static PGOSampleType noneType = PGOSampleType::NoneType();
1200             return &noneType;
1201         }
1202         ASSERT(type_->IsScalarOpType());
1203         return static_cast<const PGOSampleType*>(type_);
1204     }
1205 
IsPGOSampleType()1206     bool IsPGOSampleType() const
1207     {
1208         if (type_ == nullptr) {
1209             return false;
1210         }
1211         return type_->IsScalarOpType();
1212     }
1213 
HasNumber()1214     bool HasNumber() const
1215     {
1216         return GetPGOSampleType()->HasNumber();
1217     }
1218 
IsBoolean()1219     bool IsBoolean() const
1220     {
1221         return GetPGOSampleType()->IsBoolean();
1222     }
1223 
IsString()1224     bool IsString() const
1225     {
1226         return GetPGOSampleType()->IsString();
1227     }
1228 
IsHeapObject()1229     bool IsHeapObject() const
1230     {
1231         return GetPGOSampleType()->IsHeapObject();
1232     }
1233 
IsNumberOrString()1234     bool IsNumberOrString() const
1235     {
1236         return GetPGOSampleType()->IsNumberOrString();
1237     }
1238 
GetPGORWOpType()1239     const PGORWOpType* GetPGORWOpType()
1240     {
1241         if (type_ == nullptr) {
1242             static PGORWOpType noneType;
1243             return &noneType;
1244         }
1245         ASSERT(type_->IsRwOpType());
1246         return static_cast<const PGORWOpType*>(type_);
1247     }
1248 
GetPGODefineOpType()1249     const PGODefineOpType* GetPGODefineOpType()
1250     {
1251         if (type_ == nullptr) {
1252             static PGODefineOpType noneType;
1253             return &noneType;
1254         }
1255         ASSERT(type_->IsDefineOpType());
1256         return static_cast<const PGODefineOpType*>(type_);
1257     }
1258 
1259 private:
1260     const PGOType *type_;
1261 };
1262 } // namespace panda::ecmascript::pgo
1263 #endif  // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILER_TYPE_H
1264