• 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_TYPE_H
17 #define ECMASCRIPT_PGO_PROFILER_TYPE_H
18 
19 #include <stdint.h>
20 #include <string>
21 #include <variant>
22 
23 #include "macros.h"
24 
25 namespace panda::ecmascript {
26 class ClassType {
27 public:
28     ClassType() = default;
ClassType(int32_t type)29     explicit ClassType(int32_t type) : type_(type) {}
30 
IsNone()31     bool IsNone() const
32     {
33         return type_ == 0;
34     }
35 
GetClassType()36     int32_t GetClassType() const
37     {
38         return type_;
39     }
40 
41     bool operator<(const ClassType &right) const
42     {
43         return type_ < right.type_;
44     }
45 
46     bool operator!=(const ClassType &right) const
47     {
48         return type_ != right.type_;
49     }
50 
51     bool operator==(const ClassType &right) const
52     {
53         return type_ == right.type_;
54     }
55 
GetTypeString()56     std::string GetTypeString() const
57     {
58         return std::to_string(type_);
59     }
60 
61 private:
62     int32_t type_ { 0 };
63 };
64 
65 class PGOType {
66 public:
67     enum class TypeKind : uint8_t {
68         SCALAR_OP_TYPE,
69         RW_OP_TYPE,
70     };
71     PGOType() = default;
PGOType(TypeKind kind)72     explicit PGOType(TypeKind kind) : kind_(kind) {}
73 
IsScalarOpType()74     bool IsScalarOpType() const
75     {
76         return kind_ == TypeKind::SCALAR_OP_TYPE;
77     }
78 
IsRwOpType()79     bool IsRwOpType() const
80     {
81         return kind_ == TypeKind::RW_OP_TYPE;
82     }
83 
84 private:
85     TypeKind kind_ { TypeKind::SCALAR_OP_TYPE };
86 };
87 
88 /**
89  * | INT    \          -> INT_OVERFLOW \
90  * |           NUMBER                    NUMBER_HETEROE1
91  * | DOUBLE /                          /
92  */
93 class PGOSampleType : public PGOType {
94 public:
95     enum class Type : uint32_t {
96         NONE = 0x0ULL,
97         INT = 0x1ULL,                       // 00000001
98         INT_OVERFLOW = (0x1ULL << 1) | INT, // 00000011
99         DOUBLE = 0x1ULL << 2,               // 00000100
100         NUMBER = INT | DOUBLE,              // 00000101
101         NUMBER1 = INT_OVERFLOW | DOUBLE,    // 00000111
102         BOOLEAN = 0x1ULL << 3,
103         UNDEFINED_OR_NULL = 0x1ULL << 4,
104         SPECIAL = 0x1ULL << 5,
105         BOOLEAN_OR_SPECIAL = BOOLEAN | SPECIAL,
106         STRING = 0x1ULL << 6,
107         BIG_INT = 0x1ULL << 7,
108         HEAP_OBJECT = 0x1ULL << 8,
109         HEAP_OR_UNDEFINED_OR_NULL = HEAP_OBJECT | UNDEFINED_OR_NULL,
110         ANY = 0x3FFULL,
111     };
112 
PGOSampleType()113     PGOSampleType() : type_(Type::NONE) {};
114 
PGOSampleType(Type type)115     explicit PGOSampleType(Type type) : type_(type) {};
PGOSampleType(uint32_t type)116     explicit PGOSampleType(uint32_t type) : type_(Type(type)) {};
PGOSampleType(ClassType type)117     explicit PGOSampleType(ClassType type) : type_(type) {}
118 
CreateClassType(int32_t classType)119     static PGOSampleType CreateClassType(int32_t classType)
120     {
121         return PGOSampleType(ClassType(classType));
122     }
123 
NoneType()124     static PGOSampleType NoneType()
125     {
126         return PGOSampleType(Type::NONE);
127     }
128 
None()129     static int32_t None()
130     {
131         return static_cast<int32_t>(Type::NONE);
132     }
133 
AnyType()134     static int32_t AnyType()
135     {
136         return static_cast<int32_t>(Type::ANY);
137     }
138 
IntType()139     static int32_t IntType()
140     {
141         return static_cast<int32_t>(Type::INT);
142     }
143 
IntOverFlowType()144     static int32_t IntOverFlowType()
145     {
146         return static_cast<int32_t>(Type::INT_OVERFLOW);
147     }
148 
DoubleType()149     static int32_t DoubleType()
150     {
151         return static_cast<int32_t>(Type::DOUBLE);
152     }
153 
NumberType()154     static int32_t NumberType()
155     {
156         return static_cast<int32_t>(Type::NUMBER);
157     }
158 
HeapObjectType()159     static int32_t HeapObjectType()
160     {
161         return static_cast<int32_t>(Type::HEAP_OBJECT);
162     }
163 
UndefineOrNullType()164     static int32_t UndefineOrNullType()
165     {
166         return static_cast<int32_t>(Type::UNDEFINED_OR_NULL);
167     }
168 
BooleanType()169     static int32_t BooleanType()
170     {
171         return static_cast<int32_t>(Type::BOOLEAN);
172     }
173 
StringType()174     static int32_t StringType()
175     {
176         return static_cast<int32_t>(Type::STRING);
177     }
178 
BigIntType()179     static int32_t BigIntType()
180     {
181         return static_cast<int32_t>(Type::BIG_INT);
182     }
183 
SpecialType()184     static int32_t SpecialType()
185     {
186         return static_cast<int32_t>(Type::SPECIAL);
187     }
188 
CombineType(int32_t curType,int32_t newType)189     static int32_t CombineType(int32_t curType, int32_t newType)
190     {
191         return static_cast<int32_t>(static_cast<uint32_t>(curType) | static_cast<uint32_t>(newType));
192     }
193 
NoneClassType()194     static PGOSampleType NoneClassType()
195     {
196         return PGOSampleType(ClassType());
197     }
198 
CombineType(PGOSampleType type)199     PGOSampleType CombineType(PGOSampleType type)
200     {
201         if (type_.index() == 0) {
202             type_ =
203                 Type(static_cast<uint32_t>(std::get<Type>(type_)) | static_cast<uint32_t>(std::get<Type>(type.type_)));
204         } else {
205             SetType(type);
206         }
207         return *this;
208     }
209 
CombineCallTargetType(PGOSampleType type)210     PGOSampleType CombineCallTargetType(PGOSampleType type)
211     {
212         ASSERT(type_.index() == 1);
213         int32_t oldMethodId = GetClassType().GetClassType();
214         int32_t newMethodId = type.GetClassType().GetClassType();
215         // If we have recorded a valid method if before, invalidate it.
216         if ((oldMethodId != newMethodId) && (oldMethodId != 0)) {
217             type_ = ClassType(0);
218         }
219         return *this;
220     }
221 
SetType(PGOSampleType type)222     void SetType(PGOSampleType type)
223     {
224         type_ = type.type_;
225     }
226 
GetTypeString()227     std::string GetTypeString() const
228     {
229         if (type_.index() == 0) {
230             return std::to_string(static_cast<uint32_t>(std::get<Type>(type_)));
231         } else {
232             return std::get<ClassType>(type_).GetTypeString();
233         }
234     }
235 
IsClassType()236     bool IsClassType() const
237     {
238         return type_.index() == 1;
239     }
240 
GetClassType()241     ClassType GetClassType() const
242     {
243         ASSERT(IsClassType());
244         return std::get<ClassType>(type_);
245     }
246 
IsAny()247     bool IsAny() const
248     {
249         return type_.index() == 0 && std::get<Type>(type_) == Type::ANY;
250     }
251 
IsNone()252     bool IsNone() const
253     {
254         return type_.index() == 0 && std::get<Type>(type_) == Type::NONE;
255     }
256 
IsInt()257     bool IsInt() const
258     {
259         return type_.index() == 0 && std::get<Type>(type_) == Type::INT;
260     }
261 
IsIntOverFlow()262     bool IsIntOverFlow() const
263     {
264         return type_.index() == 0 && std::get<Type>(type_) == Type::INT_OVERFLOW;
265     }
266 
IsDouble()267     bool IsDouble() const
268     {
269         return type_.index() == 0 && std::get<Type>(type_) == Type::DOUBLE;
270     }
271 
IsNumber()272     bool IsNumber() const
273     {
274         if (type_.index() != 0) {
275             return false;
276         }
277         switch (std::get<Type>(type_)) {
278             case Type::INT:
279             case Type::INT_OVERFLOW:
280             case Type::DOUBLE:
281             case Type::NUMBER:
282             case Type::NUMBER1:
283                 return true;
284             default:
285                 return false;
286         }
287     }
288 
289     bool operator<(const PGOSampleType &right) const
290     {
291         return type_ < right.type_;
292     }
293 
294     bool operator!=(const PGOSampleType &right) const
295     {
296         return type_ != right.type_;
297     }
298 
299     bool operator==(const PGOSampleType &right) const
300     {
301         return type_ == right.type_;
302     }
303 
304 private:
305     std::variant<Type, ClassType> type_;
306 };
307 
308 enum class PGOObjKind {
309     LOCAL,
310     PROTOTYPE,
311     CONSTRUCTOR,
312     ELEMENT,
313 };
314 
315 class PGOObjectInfo {
316 public:
PGOObjectInfo()317     PGOObjectInfo() : type_(ClassType()), objKind_(PGOObjKind::LOCAL) {}
PGOObjectInfo(ClassType type,PGOObjKind kind)318     PGOObjectInfo(ClassType type, PGOObjKind kind) : type_(type), objKind_(kind) {}
319 
GetInfoString()320     std::string GetInfoString() const
321     {
322         std::string result = type_.GetTypeString();
323         result += "(";
324         if (objKind_ == PGOObjKind::CONSTRUCTOR) {
325             result += "c";
326         } else if (objKind_ == PGOObjKind::PROTOTYPE) {
327             result += "p";
328         } else if (objKind_ == PGOObjKind::ELEMENT) {
329             result += "e";
330         } else {
331             result += "l";
332         }
333         result += ")";
334         return result;
335     }
336 
GetClassType()337     ClassType GetClassType() const
338     {
339         return type_;
340     }
341 
IsNone()342     bool IsNone() const
343     {
344         return type_.IsNone();
345     }
346 
InConstructor()347     bool InConstructor() const
348     {
349         return objKind_ == PGOObjKind::CONSTRUCTOR;
350     }
351 
352     bool operator<(const PGOObjectInfo &right) const
353     {
354         return type_ < right.type_ || objKind_ < right.objKind_;
355     }
356 
357     bool operator==(const PGOObjectInfo &right) const
358     {
359         return type_ == right.type_ && objKind_ == right.objKind_;
360     }
361 
362 private:
363     ClassType type_ { ClassType() };
364     PGOObjKind objKind_ { PGOObjKind::LOCAL };
365 };
366 
367 class PGORWOpType : public PGOType {
368 public:
PGORWOpType()369     PGORWOpType() : PGOType(TypeKind::RW_OP_TYPE), count_(0) {};
370 
Merge(const PGORWOpType & type)371     void Merge(const PGORWOpType &type)
372     {
373         for (uint32_t i = 0; i < type.count_; i++) {
374             AddObjectInfo(type.infos_[i]);
375         }
376     }
377 
AddObjectInfo(const PGOObjectInfo & info)378     void AddObjectInfo(const PGOObjectInfo &info)
379     {
380         if (info.IsNone()) {
381             return;
382         }
383         uint32_t count = 0;
384         for (; count < count_; count++) {
385             if (infos_[count] == info) {
386                 return;
387             }
388         }
389         if (count < static_cast<uint32_t>(POLY_CASE_NUM)) {
390             infos_[count] = info;
391             count_++;
392         } else {
393             LOG_ECMA(DEBUG) << "Class type exceeds 4, discard";
394         }
395     }
396 
GetObjectInfo(uint32_t index)397     PGOObjectInfo GetObjectInfo(uint32_t index) const
398     {
399         ASSERT(index < count_);
400         return infos_[index];
401     }
402 
GetCount()403     uint32_t GetCount() const
404     {
405         return count_;
406     }
407 
408 private:
409     static constexpr int POLY_CASE_NUM = 4;
410     uint32_t count_ = 0;
411     PGOObjectInfo infos_[POLY_CASE_NUM];
412 };
413 } // namespace panda::ecmascript
414 #endif // ECMASCRIPT_PGO_PROFILER_TYPE_H
415