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