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