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 <string> 21 #include <variant> 22 23 #include "ecmascript/builtin_entries.h" 24 #include "ecmascript/elements.h" 25 #include "ecmascript/js_hclass.h" 26 #include "ecmascript/log.h" 27 #include "ecmascript/log_wrapper.h" 28 #include "ecmascript/pgo_profiler/pgo_context.h" 29 #include "ecmascript/pgo_profiler/pgo_utils.h" 30 #include "ecmascript/on_heap.h" 31 #include "libpandabase/utils/bit_field.h" 32 #include "macros.h" 33 34 namespace panda::ecmascript::pgo { 35 class ProfileTypeRef; 36 class PGOContext; 37 38 using ApEntityId = pgo::ApEntityId; 39 40 class ProfileType { 41 public: 42 enum class Kind : uint8_t { 43 ClassId, 44 LiteralId, 45 BuiltinsId, 46 LegacyKind = BuiltinsId, 47 MethodId, // method offset of js function 48 BuiltinFunctionId, // function index of registered function 49 RecordClassId, 50 PrototypeId, 51 ConstructorId, 52 MegaStateKinds, 53 TotalKinds, 54 UnknowId 55 }; 56 57 static constexpr uint32_t RECORD_ID_FOR_BUNDLE = 1; 58 59 static const ProfileType PROFILE_TYPE_NONE; 60 61 static constexpr uint32_t ID_BITFIELD_NUM = 32; 62 static constexpr uint32_t ABC_ID_BITFIELD_NUM = 20; 63 static constexpr uint32_t KIND_BITFIELD_NUM = 11; 64 using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>; 65 using AbcIdBits = IdBits::NextField<uint32_t, ABC_ID_BITFIELD_NUM>; 66 using KindBits = AbcIdBits::NextField<Kind, KIND_BITFIELD_NUM>; 67 using IsRootBits = KindBits::NextFlag; 68 69 class BuiltinsId { 70 public: 71 static constexpr uint32_t BUILTINS_ID_NUM = 16; 72 using BuiltinsIdBits = BitField<JSType, 0, BUILTINS_ID_NUM>; 73 74 explicit BuiltinsId() = default; BuiltinsId(uint32_t id)75 explicit BuiltinsId(uint32_t id) : id_(id) {} 76 GetId()77 uint32_t GetId() const 78 { 79 return id_; 80 } 81 SetBuiltinsId(JSType type)82 BuiltinsId SetBuiltinsId(JSType type) 83 { 84 id_ = BuiltinsIdBits::Update(id_, type); 85 return *this; 86 } 87 GetBuiltinsId()88 JSType GetBuiltinsId() const 89 { 90 return BuiltinsIdBits::Decode(id_); 91 } 92 93 protected: 94 uint32_t id_ { 0 }; 95 }; 96 97 class BuiltinsArrayId : public BuiltinsId { 98 public: 99 // BuilitinsArray second bit field 100 static constexpr uint32_t OLD_ELEMENTS_KIND_BITFIELD_NUM = 5; 101 static constexpr uint32_t NEW_ELEMENTS_KIND_BITFIELD_NUM = 5; 102 using OldElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, OLD_ELEMENTS_KIND_BITFIELD_NUM>; 103 using NewElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, NEW_ELEMENTS_KIND_BITFIELD_NUM>; 104 105 explicit BuiltinsArrayId() = default; BuiltinsArrayId(uint32_t id)106 explicit BuiltinsArrayId(uint32_t id) : BuiltinsId(id) {} 107 UpdateElementsKind(ElementsKind kind)108 BuiltinsArrayId UpdateElementsKind(ElementsKind kind) 109 { 110 id_ = OldElementsKindBits::Update(id_, kind); 111 return *this; 112 } 113 GetElementsKind()114 ElementsKind GetElementsKind() const 115 { 116 return OldElementsKindBits::Decode(id_); 117 } 118 UpdateTransitionElementsKind(ElementsKind kind)119 BuiltinsArrayId UpdateTransitionElementsKind(ElementsKind kind) 120 { 121 id_ = NewElementsKindBits::Update(id_, kind); 122 return *this; 123 } 124 GetTransitionElementsKind()125 ElementsKind GetTransitionElementsKind() const 126 { 127 return NewElementsKindBits::Decode(id_); 128 } 129 }; 130 131 class BuiltinsTypedArrayId : public BuiltinsId { 132 public: 133 // BuilitinsTypedArray second bit field 134 static constexpr uint8_t ON_HEAP_MODE_BITFIELD_NUM = 2; 135 using OnHeapModeBits = BuiltinsIdBits::NextField<OnHeapMode, ON_HEAP_MODE_BITFIELD_NUM>; 136 137 explicit BuiltinsTypedArrayId() = default; BuiltinsTypedArrayId(uint32_t id)138 explicit BuiltinsTypedArrayId(uint32_t id) : BuiltinsId(id) {} 139 UpdateOnHeapMode(OnHeapMode onHeapMode)140 BuiltinsTypedArrayId UpdateOnHeapMode(OnHeapMode onHeapMode) 141 { 142 id_ = OnHeapModeBits::Update(id_, onHeapMode); 143 return *this; 144 } 145 GetOnHeapMode()146 OnHeapMode GetOnHeapMode() const 147 { 148 return OnHeapModeBits::Decode(id_); 149 } 150 }; 151 152 static_assert(KindBits::IsValid(Kind::TotalKinds)); 153 154 ProfileType() = default; ProfileType(uint64_t rawType)155 explicit ProfileType(uint64_t rawType) : type_(rawType) {}; 156 ProfileType(PGOContext &context, ProfileTypeRef typeRef); 157 ProfileType(ApEntityId abcId, uint32_t type, Kind kind = Kind::ClassId, bool root = false) 158 { 159 if (UNLIKELY(!IdBits::IsValid(type))) { 160 type_ = 0; 161 } else { 162 UpdateAbcId(abcId); 163 UpdateId(type); 164 UpdateKind(kind); 165 UpdateIsRootFlag(root); 166 } 167 } 168 CreateMegeType()169 static ProfileType CreateMegeType() 170 { 171 ProfileType type; 172 type.UpdateKind(Kind::MegaStateKinds); 173 return type; 174 } 175 CreateBuiltinsArray(ApEntityId abcId,JSType type,ElementsKind kind,ElementsKind transitionKind)176 static ProfileType CreateBuiltinsArray(ApEntityId abcId, JSType type, ElementsKind kind, 177 ElementsKind transitionKind) 178 { 179 auto id = BuiltinsArrayId().UpdateElementsKind(kind).UpdateTransitionElementsKind(transitionKind) 180 .SetBuiltinsId(type).GetId(); 181 return ProfileType(abcId, id, Kind::BuiltinsId); 182 } 183 CreateBuiltinsTypedArray(ApEntityId abcId,JSType type,OnHeapMode onHeap)184 static ProfileType CreateBuiltinsTypedArray(ApEntityId abcId, JSType type, OnHeapMode onHeap) 185 { 186 auto id = BuiltinsTypedArrayId().UpdateOnHeapMode(onHeap).SetBuiltinsId(type).GetId(); 187 return ProfileType(abcId, id, Kind::BuiltinsId); 188 } 189 CreateBuiltins(ApEntityId abcId,JSType type)190 static ProfileType CreateBuiltins(ApEntityId abcId, JSType type) 191 { 192 auto id = BuiltinsId().SetBuiltinsId(type).GetId(); 193 return ProfileType(abcId, id, Kind::BuiltinsId); 194 } 195 196 ProfileType &Remap(const PGOContext &context); 197 IsNone()198 bool IsNone() const 199 { 200 return type_ == PROFILE_TYPE_NONE.type_; 201 } 202 GetRaw()203 uint64_t GetRaw() const 204 { 205 return type_; 206 } 207 IsRootType()208 bool IsRootType() const 209 { 210 return IsRootBits::Decode(type_); 211 } 212 IsBuiltinsType()213 bool IsBuiltinsType() const 214 { 215 return GetKind() == Kind::BuiltinsId; 216 } 217 IsClassType()218 bool IsClassType() const 219 { 220 return GetKind() == Kind::ClassId; 221 } 222 IsMethodId()223 bool IsMethodId() const 224 { 225 return GetKind() == Kind::MethodId; 226 } 227 IsBuiltinFunctionId()228 bool IsBuiltinFunctionId() const 229 { 230 return GetKind() == Kind::BuiltinFunctionId; 231 } 232 IsLiteralType()233 bool IsLiteralType() const 234 { 235 return GetKind() == Kind::LiteralId; 236 } 237 IsConstructor()238 bool IsConstructor() const 239 { 240 return GetKind() == Kind::ConstructorId; 241 } 242 IsPrototype()243 bool IsPrototype() const 244 { 245 return GetKind() == Kind::PrototypeId; 246 } 247 IsMegaStateType()248 bool IsMegaStateType() const 249 { 250 return GetKind() == Kind::MegaStateKinds; 251 } 252 GetId()253 uint32_t GetId() const 254 { 255 return IdBits::Decode(type_); 256 } 257 GetKind()258 Kind GetKind() const 259 { 260 return KindBits::Decode(type_); 261 } 262 GetAbcId()263 ApEntityId GetAbcId() const 264 { 265 return AbcIdBits::Decode(type_); 266 } 267 UpdateAbcId(ApEntityId abcId)268 void UpdateAbcId(ApEntityId abcId) 269 { 270 type_ = AbcIdBits::Update(type_, abcId); 271 } 272 273 bool operator<(const ProfileType &right) const 274 { 275 return type_ < right.type_; 276 } 277 278 bool operator!=(const ProfileType &right) const 279 { 280 return type_ != right.type_; 281 } 282 283 bool operator==(const ProfileType &right) const 284 { 285 return type_ == right.type_; 286 } 287 GetTypeString()288 std::string GetTypeString() const 289 { 290 std::stringstream stream; 291 stream << "Type: " << "(isRoot: " << IsRootType() << 292 ", kind: " << std::showbase << std::dec << static_cast<uint32_t>(GetKind()) << 293 ", abcId: " << GetAbcId() << 294 ", id: " << GetId() << ")"; 295 return stream.str(); 296 } 297 UpdateId(uint32_t id)298 void UpdateId(uint32_t id) 299 { 300 type_ = IdBits::Update(type_, id); 301 } 302 UpdateKind(Kind kind)303 void UpdateKind(Kind kind) 304 { 305 type_ = KindBits::Update(type_, kind); 306 } 307 UpdateIsRootFlag(bool root)308 void UpdateIsRootFlag(bool root) 309 { 310 type_ = IsRootBits::Update(type_, root); 311 } 312 IsValidCallMethodId()313 bool IsValidCallMethodId() const 314 { 315 return GetCallMethodId() > 0; 316 } 317 GetCallMethodId()318 uint32_t GetCallMethodId() const 319 { 320 ASSERT(IsMethodId()); 321 return GetId(); 322 } 323 GetBuiltinsId()324 JSType GetBuiltinsId() const 325 { 326 ASSERT(IsBuiltinsType()); 327 auto builtinsId = BuiltinsId(GetId()); 328 return builtinsId.GetBuiltinsId(); 329 } 330 GetElementsKind()331 ElementsKind GetElementsKind() const 332 { 333 ASSERT(IsBuiltinsArray()); 334 auto builtinsArrayId = BuiltinsArrayId(GetId()); 335 return builtinsArrayId.GetElementsKind(); 336 } 337 IsBuiltinsString()338 bool IsBuiltinsString() const 339 { 340 if (IsBuiltinsType()) { 341 JSType type = GetBuiltinsId(); 342 return type >= JSType::STRING_FIRST && type <= JSType::STRING_LAST; 343 } 344 return false; 345 } 346 IsBuiltinsArray()347 bool IsBuiltinsArray() const 348 { 349 if (IsBuiltinsType()) { 350 JSType type = GetBuiltinsId(); 351 return type == JSType::JS_ARRAY; 352 } 353 return false; 354 } 355 IsBuiltinsTypeArray()356 bool IsBuiltinsTypeArray() const 357 { 358 if (IsBuiltinsType()) { 359 JSType type = GetBuiltinsId(); 360 return type > JSType::JS_TYPED_ARRAY_FIRST && type <= JSType::JS_TYPED_ARRAY_LAST; 361 } 362 return false; 363 } 364 365 private: UpdateId(uint64_t type)366 void UpdateId(uint64_t type) 367 { 368 type_ = IdBits::Update(type_, type); 369 } 370 371 uint64_t type_ {0}; 372 }; 373 374 struct HashProfileType { operatorHashProfileType375 uint64_t operator()(const ProfileType &profileType) const 376 { 377 return profileType.GetRaw(); 378 } 379 }; 380 381 class ProfileTypeRef { 382 public: 383 ProfileTypeRef() = default; ProfileTypeRef(ApEntityId type)384 explicit ProfileTypeRef(ApEntityId type) 385 { 386 UpdateId(type); 387 } 388 389 ProfileTypeRef(PGOContext &context, const ProfileType &type); 390 391 ProfileTypeRef &Remap(const PGOContext &context); 392 IsNone()393 bool IsNone() const 394 { 395 return typeId_ == 0; 396 } 397 IsBuiltinsArray()398 bool IsBuiltinsArray() const 399 { 400 return false; 401 } 402 IsConstructor()403 bool IsConstructor() const 404 { 405 return false; 406 } 407 IsMegaStateType()408 bool IsMegaStateType() const 409 { 410 return false; 411 } 412 GetId()413 ApEntityId GetId() const 414 { 415 return typeId_; 416 } 417 418 bool operator<(const ProfileTypeRef &right) const 419 { 420 return typeId_ < right.typeId_; 421 } 422 423 bool operator==(const ProfileTypeRef &right) const 424 { 425 return typeId_ == right.typeId_; 426 } 427 GetTypeString()428 std::string GetTypeString() const 429 { 430 return std::to_string(typeId_); 431 } 432 UpdateId(ApEntityId typeId)433 void UpdateId(ApEntityId typeId) 434 { 435 typeId_ = typeId; 436 } 437 438 private: 439 ApEntityId typeId_ {0}; 440 }; 441 static_assert(sizeof(ProfileTypeRef) == sizeof(uint32_t)); 442 443 class ProfileTypeLegacy { 444 public: 445 static constexpr uint32_t ID_BITFIELD_NUM = 29; 446 static constexpr uint32_t KIND_BITFIELD_NUM = 3; 447 using IdBits = BitField<uint32_t, 0, ID_BITFIELD_NUM>; 448 using KindBits = IdBits::NextField<ProfileType::Kind, KIND_BITFIELD_NUM>; 449 450 // legacy size check. for version lower than WIDE_CLASS_TYPE_MINI_VERSION, we should consider the legacy scenario. 451 static_assert(KindBits::IsValid(ProfileType::Kind::LegacyKind)); 452 453 explicit ProfileTypeLegacy(uint32_t type, ProfileType::Kind kind = ProfileType::Kind::ClassId) 454 { 455 if (!IdBits::IsValid(type)) { 456 type_ = 0; 457 } else { 458 UpdateId(type); 459 UpdateKind(kind); 460 } 461 } 462 ProfileTypeLegacy(ProfileTypeRef profileTypeRef)463 explicit ProfileTypeLegacy(ProfileTypeRef profileTypeRef) : type_(profileTypeRef.GetId()) {} 464 IsNone()465 bool IsNone() const 466 { 467 return type_ == 0; 468 } 469 GetRaw()470 uint32_t GetRaw() const 471 { 472 return type_; 473 } 474 GetId()475 uint32_t GetId() const 476 { 477 return IdBits::Decode(type_); 478 } 479 GetKind()480 ProfileType::Kind GetKind() const 481 { 482 return KindBits::Decode(type_); 483 } 484 485 private: UpdateId(uint32_t type)486 void UpdateId(uint32_t type) 487 { 488 type_ = IdBits::Update(type_, type); 489 } 490 UpdateKind(ProfileType::Kind kind)491 void UpdateKind(ProfileType::Kind kind) 492 { 493 type_ = KindBits::Update(type_, kind); 494 } 495 uint32_t type_ {0}; 496 }; 497 498 class TraProfileType { 499 public: TraProfileType(ProfileType root,ProfileType child)500 TraProfileType(ProfileType root, ProfileType child) : root_(root), child_(child) {} 501 502 private: 503 ProfileType root_; 504 ProfileType child_; 505 }; 506 } // namespace panda::ecmascript::pgo 507 #endif // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILE_TYPE_H 508