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