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_PROFILER_TYPE_H 17 #define ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILER_TYPE_H 18 19 #include <stdint.h> 20 #include <string> 21 #include <variant> 22 #include <vector> 23 24 #include "ecmascript/elements.h" 25 #include "ecmascript/js_hclass.h" 26 #include "ecmascript/mem/region.h" 27 #include "ecmascript/log_wrapper.h" 28 #include "ecmascript/pgo_profiler/pgo_utils.h" 29 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h" 30 #include "libpandabase/utils/bit_field.h" 31 #include "macros.h" 32 33 namespace panda::ecmascript::pgo { 34 class PGOContext; 35 class PGOType { 36 public: 37 enum class TypeKind : uint8_t { 38 SCALAR_OP_TYPE, 39 RW_OP_TYPE, 40 DEFINE_OP_TYPE, 41 PROTO_TRANSITION_TYPE, 42 }; 43 PGOType() = default; PGOType(TypeKind kind)44 explicit PGOType(TypeKind kind) : kind_(kind) {} 45 IsScalarOpType()46 bool IsScalarOpType() const 47 { 48 return kind_ == TypeKind::SCALAR_OP_TYPE; 49 } 50 IsRwOpType()51 bool IsRwOpType() const 52 { 53 return kind_ == TypeKind::RW_OP_TYPE; 54 } 55 IsDefineOpType()56 bool IsDefineOpType() const 57 { 58 return kind_ == TypeKind::DEFINE_OP_TYPE; 59 } 60 IsProtoTransitionType()61 bool IsProtoTransitionType() const 62 { 63 return kind_ == TypeKind::PROTO_TRANSITION_TYPE; 64 } 65 66 private: 67 TypeKind kind_ {TypeKind::SCALAR_OP_TYPE}; 68 }; 69 70 /** 71 * | INT \ -> INT_OVERFLOW \ 72 * | NUMBER NUMBER_HETEROE1 73 * | DOUBLE / / 74 */ 75 template <typename PGOProfileType> 76 class PGOSampleTemplate : public PGOType { 77 public: 78 static constexpr int WEIGHT_BITS = 11; 79 static constexpr int WEIGHT_START_BIT = 10; 80 static constexpr int WEIGHT_TRUE_START_BIT = WEIGHT_START_BIT + WEIGHT_BITS; 81 static constexpr int WEIGHT_MASK = (1 << WEIGHT_BITS) - 1; 82 static constexpr int WEIGHT_THRESHOLD = WEIGHT_MASK; // 2047 83 84 enum class Type : uint32_t { 85 NONE = 0x0ULL, 86 INT = 0x1ULL, // 00000001 87 INT_OVERFLOW = (0x1ULL << 1) | INT, // 00000011 88 DOUBLE = 0x1ULL << 2, // 00000100 89 NUMBER = INT | DOUBLE, // 00000101 90 NUMBER1 = INT_OVERFLOW | DOUBLE, // 00000111 91 BOOLEAN = 0x1ULL << 3, 92 UNDEFINED_OR_NULL = 0x1ULL << 4, 93 SPECIAL = 0x1ULL << 5, 94 BOOLEAN_OR_SPECIAL = BOOLEAN | SPECIAL, 95 STRING = 0x1ULL << 6, 96 NUMBER_OR_STRING = NUMBER | STRING, 97 BIG_INT = 0x1ULL << 7, 98 HEAP_OBJECT = 0x1ULL << 8, 99 HEAP_OR_UNDEFINED_OR_NULL = HEAP_OBJECT | UNDEFINED_OR_NULL, 100 ANY = (0x1ULL << WEIGHT_START_BIT) - 1, 101 }; 102 PGOSampleTemplate()103 PGOSampleTemplate() : type_(Type::NONE) {}; 104 PGOSampleTemplate(Type type)105 explicit PGOSampleTemplate(Type type) : type_(type) {}; PGOSampleTemplate(uint32_t type)106 explicit PGOSampleTemplate(uint32_t type) : type_(Type(type)) {}; PGOSampleTemplate(PGOProfileType type)107 explicit PGOSampleTemplate(PGOProfileType type) : type_(type) {} 108 109 template <typename FromType> ConvertFrom(PGOContext & context,const FromType & from)110 static PGOSampleTemplate ConvertFrom(PGOContext &context, const FromType &from) 111 { 112 if (from.IsProfileType()) { 113 return PGOSampleTemplate(PGOProfileType(context, from.GetProfileType())); 114 } 115 return PGOSampleTemplate(static_cast<PGOSampleTemplate::Type>(from.GetType())); 116 } 117 118 static PGOSampleTemplate CreateProfileType(ApEntityId recordId, int32_t profileType, 119 typename ProfileType::Kind kind = ProfileType::Kind::ClassId, 120 bool isRoot = false) 121 { 122 return PGOSampleTemplate(PGOProfileType(recordId, profileType, kind, isRoot)); 123 } 124 NoneType()125 static PGOSampleTemplate NoneType() 126 { 127 return PGOSampleTemplate(Type::NONE); 128 } 129 None()130 static int32_t None() 131 { 132 return static_cast<int32_t>(Type::NONE); 133 } 134 AnyType()135 static int32_t AnyType() 136 { 137 return static_cast<int32_t>(Type::ANY); 138 } 139 IntType()140 static int32_t IntType() 141 { 142 return static_cast<int32_t>(Type::INT); 143 } 144 IntOverFlowType()145 static int32_t IntOverFlowType() 146 { 147 return static_cast<int32_t>(Type::INT_OVERFLOW); 148 } 149 DoubleType()150 static int32_t DoubleType() 151 { 152 return static_cast<int32_t>(Type::DOUBLE); 153 } 154 NumberType()155 static int32_t NumberType() 156 { 157 return static_cast<int32_t>(Type::NUMBER); 158 } 159 HeapObjectType()160 static int32_t HeapObjectType() 161 { 162 return static_cast<int32_t>(Type::HEAP_OBJECT); 163 } 164 UndefineOrNullType()165 static int32_t UndefineOrNullType() 166 { 167 return static_cast<int32_t>(Type::UNDEFINED_OR_NULL); 168 } 169 BooleanType()170 static int32_t BooleanType() 171 { 172 return static_cast<int32_t>(Type::BOOLEAN); 173 } 174 StringType()175 static int32_t StringType() 176 { 177 return static_cast<int32_t>(Type::STRING); 178 } 179 NumberOrStringType()180 static int32_t NumberOrStringType() 181 { 182 return static_cast<int32_t>(Type::NUMBER_OR_STRING); 183 } 184 BigIntType()185 static int32_t BigIntType() 186 { 187 return static_cast<int32_t>(Type::BIG_INT); 188 } 189 SpecialType()190 static int32_t SpecialType() 191 { 192 return static_cast<int32_t>(Type::SPECIAL); 193 } 194 CombineType(int32_t curType,int32_t newType)195 static int32_t CombineType(int32_t curType, int32_t newType) 196 { 197 return static_cast<int32_t>(static_cast<uint32_t>(curType) | static_cast<uint32_t>(newType)); 198 } 199 NoneProfileType()200 static PGOSampleTemplate NoneProfileType() 201 { 202 return PGOSampleTemplate(PGOProfileType()); 203 } 204 CombineType(PGOSampleTemplate type)205 PGOSampleTemplate CombineType(PGOSampleTemplate type) 206 { 207 if (IsPrimitiveType()) { 208 if (std::holds_alternative<PGOProfileType>(type.type_)) { 209 LOG_ECMA(ERROR) << "The type is PGOProfileType, but need a Type"; 210 return *this; 211 } 212 auto oldType = static_cast<uint32_t>(std::get<Type>(type_)); 213 oldType = oldType & static_cast<uint32_t>(AnyType()); 214 type_ = 215 Type(oldType | static_cast<uint32_t>(std::get<Type>(type.type_))); 216 } else { 217 this->SetType(type); 218 } 219 return *this; 220 } 221 CombineCallTargetType(PGOSampleTemplate type)222 PGOSampleTemplate CombineCallTargetType(PGOSampleTemplate type) 223 { 224 ASSERT(type_.index() == 1); 225 ProfileType::Kind oldKind = GetProfileType().GetKind(); 226 ProfileType::Kind newKind = type.GetProfileType().GetKind(); 227 uint32_t oldMethodId = GetProfileType().GetId(); 228 uint32_t newMethodId = type.GetProfileType().GetId(); 229 // If we have recorded a valid method if before, invalidate it. 230 if ((oldMethodId != 0) && 231 ((oldKind != newKind) || (oldMethodId != newMethodId))) { 232 type_ = ProfileType::PROFILE_TYPE_NONE; 233 } 234 return *this; 235 } 236 SetType(PGOSampleTemplate type)237 void SetType(PGOSampleTemplate type) 238 { 239 type_ = type.type_; 240 } 241 GetTypeString()242 std::string GetTypeString() const 243 { 244 if (IsPrimitiveType()) { 245 return std::to_string(static_cast<uint32_t>(std::get<Type>(type_))); 246 } else { 247 return std::get<PGOProfileType>(type_).GetTypeString(); 248 } 249 } 250 GetTypeJson(ProfileType::StringMap & type)251 void GetTypeJson(ProfileType::StringMap &type) const 252 { 253 if (IsPrimitiveType()) { 254 type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, 255 std::to_string(static_cast<uint32_t>(std::get<Type>(type_))))); 256 } else { 257 type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, "Type")); 258 std::get<PGOProfileType>(type_).GetTypeJson(type); 259 } 260 if (IsScalarOpType()) { 261 if (!ToString().empty()) { 262 type.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, ToString())); 263 } 264 } 265 } 266 ToString()267 std::string ToString() const 268 { 269 if (IsPrimitiveType()) { 270 auto type = std::get<Type>(type_); 271 switch (type) { 272 case Type::NONE: 273 return "none"; 274 case Type::INT: 275 return "int"; 276 case Type::INT_OVERFLOW: 277 return "int_overflow"; 278 case Type::DOUBLE: 279 return "double"; 280 case Type::NUMBER: 281 return "number"; 282 case Type::NUMBER1: 283 return "number1"; 284 case Type::BOOLEAN: 285 return "boolean"; 286 case Type::UNDEFINED_OR_NULL: 287 return "undefined_or_null"; 288 case Type::SPECIAL: 289 return "special"; 290 case Type::BOOLEAN_OR_SPECIAL: 291 return "boolean_or_special"; 292 case Type::STRING: 293 return "string"; 294 case Type::BIG_INT: 295 return "big_int"; 296 case Type::HEAP_OBJECT: 297 return "heap_object"; 298 case Type::HEAP_OR_UNDEFINED_OR_NULL: 299 return "heap_or_undefined_or_null"; 300 case Type::ANY: 301 return "any"; 302 default: 303 return ""; 304 } 305 } 306 return ""; 307 } 308 IsProfileType()309 bool IsProfileType() const 310 { 311 return type_.index() == 1; 312 } 313 GetProfileType()314 PGOProfileType GetProfileType() const 315 { 316 ASSERT(IsProfileType()); 317 return std::get<PGOProfileType>(type_); 318 } 319 IsPrimitiveType()320 bool IsPrimitiveType() const 321 { 322 return type_.index() == 0; 323 } 324 GetPrimitiveType()325 Type GetPrimitiveType() const 326 { 327 ASSERT(IsPrimitiveType()); 328 auto type = static_cast<uint32_t>(std::get<Type>(type_)); 329 return Type(type & static_cast<uint32_t>(AnyType())); 330 } 331 GetWeight()332 uint32_t GetWeight() const 333 { 334 ASSERT(IsPrimitiveType()); 335 auto type = static_cast<uint32_t>(std::get<Type>(type_)); 336 return type >> WEIGHT_START_BIT; 337 } 338 IsAny()339 bool IsAny() const 340 { 341 return IsPrimitiveType() && GetPrimitiveType() == Type::ANY; 342 } 343 IsNone()344 bool IsNone() const 345 { 346 return IsPrimitiveType() && GetPrimitiveType() == Type::NONE; 347 } 348 IsInt()349 bool IsInt() const 350 { 351 return IsPrimitiveType() && GetPrimitiveType() == Type::INT; 352 } 353 IsIntOverFlow()354 bool IsIntOverFlow() const 355 { 356 return IsPrimitiveType() && GetPrimitiveType() == Type::INT_OVERFLOW; 357 } 358 IsDouble()359 bool IsDouble() const 360 { 361 return IsPrimitiveType() && GetPrimitiveType() == Type::DOUBLE; 362 } 363 IsString()364 bool IsString() const 365 { 366 return IsPrimitiveType() && GetPrimitiveType() == Type::STRING; 367 } 368 IsBigInt()369 bool IsBigInt() const 370 { 371 return type_.index() == 0 && GetPrimitiveType() == Type::BIG_INT; 372 } 373 IsBoolean()374 bool IsBoolean() const 375 { 376 return type_.index() == 0 && GetPrimitiveType() == Type::BOOLEAN; 377 } 378 IsHeapObject()379 bool IsHeapObject() const 380 { 381 return type_.index() == 0 && GetPrimitiveType() == Type::HEAP_OBJECT; 382 } 383 IsNumber()384 bool IsNumber() const 385 { 386 if (type_.index() != 0) { 387 return false; 388 } 389 auto primType = GetPrimitiveType(); 390 return primType == Type::NUMBER || primType == Type::NUMBER1; 391 } 392 IsNumberOrString()393 bool IsNumberOrString() const 394 { 395 if (type_.index() != 0) { 396 return false; 397 } 398 auto primType = GetPrimitiveType(); 399 return primType == Type::NUMBER_OR_STRING; 400 } 401 HasNumber()402 bool HasNumber() const 403 { 404 if (type_.index() != 0) { 405 return false; 406 } 407 auto primType = GetPrimitiveType(); 408 switch (primType) { 409 case Type::INT: 410 case Type::INT_OVERFLOW: 411 case Type::DOUBLE: 412 case Type::NUMBER: 413 case Type::NUMBER1: 414 return true; 415 default: 416 return false; 417 } 418 } 419 IsProfileTypeNone()420 bool IsProfileTypeNone() const 421 { 422 return type_.index() == 1 && GetProfileType() == ProfileType::PROFILE_TYPE_NONE; 423 } 424 425 bool operator<(const PGOSampleTemplate &right) const 426 { 427 return type_ < right.type_; 428 } 429 430 bool operator!=(const PGOSampleTemplate &right) const 431 { 432 return type_ != right.type_; 433 } 434 435 bool operator==(const PGOSampleTemplate &right) const 436 { 437 return type_ == right.type_; 438 } 439 GetType()440 Type GetType() const 441 { 442 ASSERT(!IsProfileType()); 443 return std::get<Type>(type_); 444 } 445 446 private: 447 std::variant<Type, PGOProfileType> type_; 448 }; 449 450 using PGOSampleType = PGOSampleTemplate<ProfileType>; 451 using PGOSampleTypeRef = PGOSampleTemplate<ProfileTypeRef>; 452 453 template <typename PGOProfileType> 454 class PGOProtoChainTemplate { 455 public: 456 static constexpr int32_t PROTO_CHAIN_MIN_COUNT = 0; 457 static constexpr int32_t PROTO_CHAIN_MAX_COUNT = 4096; 458 459 PGOProtoChainTemplate() = default; PGOProtoChainTemplate(int32_t size,int32_t count)460 PGOProtoChainTemplate(int32_t size, int32_t count) : size_(size), count_(count) {}; 461 CreateProtoChain(std::vector<std::pair<PGOProfileType,PGOProfileType>> protoChain)462 static PGOProtoChainTemplate *CreateProtoChain(std::vector<std::pair<PGOProfileType, PGOProfileType>> protoChain) 463 { 464 auto count = protoChain.size(); 465 size_t size = sizeof(PGOProtoChainTemplate); 466 if (count != 0) { 467 size += sizeof(PGOProfileType) * (count - 1) * 2; // 2 means mul by 2 468 } 469 auto result = reinterpret_cast<PGOProtoChainTemplate *>(malloc(size)); 470 if (result == nullptr) { 471 LOG_ECMA_MEM(FATAL) << "malloc failed"; 472 UNREACHABLE(); 473 } 474 new (result) PGOProtoChainTemplate(size, count); 475 PGOProfileType *curPt = &(result->rootType_); 476 for (auto iter : protoChain) { 477 *curPt = iter.first; 478 curPt = curPt + 1; 479 *curPt = iter.second; 480 curPt = curPt + 1; 481 } 482 return result; 483 } 484 DeleteProtoChain(PGOProtoChainTemplate * protoChain)485 static void DeleteProtoChain(PGOProtoChainTemplate *protoChain) 486 { 487 free(protoChain); 488 } 489 490 template <typename FromType> ConvertFrom(PGOContext & context,FromType * from)491 static PGOProtoChainTemplate *ConvertFrom(PGOContext &context, FromType *from) 492 { 493 auto count = from->GetCount(); 494 size_t size = sizeof(PGOProtoChainTemplate); 495 if (count != 0) { 496 size += sizeof(PGOProfileType) * (static_cast<size_t>(count) - 1) * 2; // 2 means mul by 2 497 } 498 auto result = reinterpret_cast<PGOProtoChainTemplate *>(malloc(size)); 499 if (result == nullptr) { 500 LOG_ECMA_MEM(FATAL) << "malloc failed"; 501 UNREACHABLE(); 502 } 503 new (result) PGOProtoChainTemplate(size, count); 504 PGOProfileType *curPt = &(result->rootType_); 505 from->IterateProtoChain([&context, &curPt] (auto rootType, auto childType) { 506 *curPt = PGOProfileType(context, rootType); 507 curPt = curPt + 1; 508 *curPt = PGOProfileType(context, childType); 509 curPt = curPt + 1; 510 }); 511 return result; 512 } 513 514 template <typename Callback> IterateProtoChain(Callback callback)515 void IterateProtoChain(Callback callback) const 516 { 517 if (count_ < PROTO_CHAIN_MIN_COUNT || count_ > PROTO_CHAIN_MAX_COUNT) { 518 return; 519 } 520 for (int i = 0; i < count_; i++) { 521 callback(*(&rootType_ + i), *(&rootType_ + i + 1)); 522 } 523 } 524 GetCount()525 int32_t GetCount() 526 { 527 return count_; 528 } 529 Size()530 int32_t Size() 531 { 532 return size_; 533 } 534 535 private: 536 int32_t size_; 537 int32_t count_; 538 PGOProfileType rootType_ {PGOProfileType()}; 539 PGOProfileType childType_ {PGOProfileType()}; 540 }; 541 542 using PGOProtoChain = PGOProtoChainTemplate<ProfileType>; 543 using PGOProtoChainRef = PGOProtoChainTemplate<ProfileTypeRef>; 544 545 enum class ProtoChainMarker : uint8_t { 546 EXSIT, 547 NOT_EXSIT, 548 }; 549 550 template <typename PGOProfileType, typename PGOSampleType> 551 class PGOObjectTemplate { 552 public: 553 PGOObjectTemplate() = default; PGOObjectTemplate(PGOProfileType type)554 PGOObjectTemplate(PGOProfileType type) : receiverType_(type) {} PGOObjectTemplate(PGOProfileType receiverType,JSHClass * receiver,JSHClass * hold,JSHClass * holdTra,PGOSampleType accessorMethod)555 PGOObjectTemplate(PGOProfileType receiverType, JSHClass *receiver, JSHClass *hold, JSHClass *holdTra, 556 PGOSampleType accessorMethod) 557 : receiverType_(receiverType), receiver_(receiver), holder_(hold), holdTra_(holdTra), 558 accessorMethod_(accessorMethod) {} PGOObjectTemplate(PGOProfileType receiverRootType,PGOProfileType receiverType,PGOProfileType holdRootType,PGOProfileType holdType,PGOProfileType holdTraRootType,PGOProfileType holdTraType,PGOSampleType accessorMethod)559 PGOObjectTemplate(PGOProfileType receiverRootType, 560 PGOProfileType receiverType, PGOProfileType holdRootType, 561 PGOProfileType holdType, PGOProfileType holdTraRootType, 562 PGOProfileType holdTraType, PGOSampleType accessorMethod) 563 : receiverRootType_(receiverRootType), receiverType_(receiverType), 564 holdRootType_(holdRootType), holdType_(holdType), 565 holdTraRootType_(holdTraRootType), holdTraType_(holdTraType), 566 accessorMethod_(accessorMethod) {} 567 AddPrototypePt(std::vector<std::pair<PGOProfileType,PGOProfileType>> protoChain)568 void AddPrototypePt(std::vector<std::pair<PGOProfileType, PGOProfileType>> protoChain) 569 { 570 protoChainMarker_ = ProtoChainMarker::EXSIT; 571 if (protoChain_ != nullptr) { 572 PGOProtoChainTemplate<PGOProfileType>::DeleteProtoChain(protoChain_); 573 } 574 protoChain_ = PGOProtoChainTemplate<PGOProfileType>::CreateProtoChain(protoChain); 575 } 576 577 template <typename FromType> ConvertFrom(PGOContext & context,const FromType & from)578 void ConvertFrom(PGOContext &context, const FromType &from) 579 { 580 receiverRootType_ = PGOProfileType(context, from.GetReceiverRootType()); 581 receiverType_ = PGOProfileType(context, from.GetReceiverType()); 582 holdRootType_ = PGOProfileType(context, from.GetHoldRootType()); 583 holdType_ = PGOProfileType(context, from.GetHoldType()); 584 holdTraRootType_ = PGOProfileType(context, from.GetHoldTraRootType()); 585 holdTraType_ = PGOProfileType(context, from.GetHoldTraType()); 586 accessorMethod_ = PGOSampleType::ConvertFrom(context, from.GetAccessorMethod()); 587 protoChainMarker_ = from.GetProtoChainMarker(); 588 } 589 GetInfoString()590 std::string GetInfoString() const 591 { 592 std::string result = "(receiverRoot"; 593 result += receiverRootType_.GetTypeString(); 594 result += ", receiver"; 595 result += receiverType_.GetTypeString(); 596 result += ", holdRoot"; 597 result += holdRootType_.GetTypeString(); 598 result += ", hold"; 599 result += holdType_.GetTypeString(); 600 result += ", holdTraRoot"; 601 result += holdTraRootType_.GetTypeString(); 602 result += ", holdTra"; 603 result += holdTraType_.GetTypeString(); 604 result += ", accessorMethod"; 605 result += accessorMethod_.GetTypeString(); 606 result += ")"; 607 return result; 608 } 609 610 template <typename T> AddTypeJson(const char * typeName,const T & type,std::string typeOffset,std::vector<ProfileType::StringMap> & typeArray)611 void AddTypeJson(const char *typeName, const T& type, std::string typeOffset, 612 std::vector<ProfileType::StringMap> &typeArray) const 613 { 614 ProfileType::StringMap typeJson; 615 typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeName)); 616 typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_OFFSET, typeOffset)); 617 type.GetTypeJson(typeJson); 618 typeArray.push_back(typeJson); 619 } 620 GetInfoJson(std::vector<ProfileType::StringMap> & typeArray,std::string typeoffset)621 void GetInfoJson(std::vector<ProfileType::StringMap> &typeArray, std::string typeoffset) const 622 { 623 AddTypeJson("receiverRootType", receiverRootType_, typeoffset, typeArray); 624 AddTypeJson("receiverType", receiverType_, typeoffset, typeArray); 625 AddTypeJson("holdRootType", holdRootType_, typeoffset, typeArray); 626 AddTypeJson("holdType", holdType_, typeoffset, typeArray); 627 AddTypeJson("holdTraRootType", holdTraRootType_, typeoffset, typeArray); 628 AddTypeJson("holdTraType", holdTraType_, typeoffset, typeArray); 629 AddTypeJson("accessorMethodType", accessorMethod_, typeoffset, typeArray); 630 } 631 GetProfileType()632 PGOProfileType GetProfileType() const 633 { 634 return receiverType_; 635 } 636 GetReceiverRootType()637 PGOProfileType GetReceiverRootType() const 638 { 639 return receiverRootType_; 640 } 641 GetReceiverType()642 PGOProfileType GetReceiverType() const 643 { 644 return receiverType_; 645 } 646 GetHoldRootType()647 PGOProfileType GetHoldRootType() const 648 { 649 return holdRootType_; 650 } 651 GetHoldType()652 PGOProfileType GetHoldType() const 653 { 654 return holdType_; 655 } 656 GetHoldTraRootType()657 PGOProfileType GetHoldTraRootType() const 658 { 659 return holdTraRootType_; 660 } 661 GetHoldTraType()662 PGOProfileType GetHoldTraType() const 663 { 664 return holdTraType_; 665 } 666 GetAccessorMethod()667 PGOSampleType GetAccessorMethod() const 668 { 669 return accessorMethod_; 670 } 671 GetProtoChainMarker()672 ProtoChainMarker GetProtoChainMarker() const 673 { 674 return protoChainMarker_; 675 } 676 GetProtoChain()677 PGOProtoChainTemplate<PGOProfileType> *GetProtoChain() const 678 { 679 return protoChain_; 680 } 681 SetProtoChain(PGOProtoChainTemplate<PGOProfileType> * protoChain)682 void SetProtoChain(PGOProtoChainTemplate<PGOProfileType> *protoChain) 683 { 684 protoChain_ = protoChain; 685 } 686 IsNone()687 bool IsNone() const 688 { 689 return receiverType_.IsNone(); 690 } 691 IsMegaStateType()692 bool IsMegaStateType() const 693 { 694 return receiverType_.IsMegaStateType(); 695 } 696 IsJITClassType()697 bool IsJITClassType() const 698 { 699 return receiverType_.IsJITClassType(); 700 } 701 InConstructor()702 bool InConstructor() const 703 { 704 return receiverType_.IsConstructor(); 705 } 706 InElement()707 bool InElement() const 708 { 709 return receiverType_.IsBuiltinsArray(); 710 } 711 712 bool operator<(const PGOObjectTemplate &right) const 713 { 714 if (receiverRootType_ != right.receiverRootType_) { 715 return receiverRootType_ < right.receiverRootType_; 716 } 717 if (receiverType_ != right.receiverType_) { 718 return receiverType_ < right.receiverType_; 719 } 720 if (holdRootType_ != right.holdRootType_) { 721 return holdRootType_ < right.holdRootType_; 722 } 723 if (holdType_ != right.holdType_) { 724 return holdType_ < right.holdType_; 725 } 726 if (holdTraRootType_ != right.holdTraRootType_) { 727 return holdTraRootType_ < right.holdTraRootType_; 728 } 729 return holdTraType_ < right.holdTraType_; 730 } 731 732 bool operator==(const PGOObjectTemplate &right) const 733 { 734 return receiverRootType_ == right.receiverRootType_ && receiverType_ == right.receiverType_ && 735 holdRootType_ == right.holdRootType_ && holdType_ == right.holdType_ && 736 holdTraRootType_ == right.holdTraRootType_ && holdTraType_ == right.holdTraType_ && 737 receiver_ == right.receiver_ && holder_ == right.holder_ && holdTra_ == right.holdTra_; 738 } 739 740 // Only Use For JIT GetReceiverHclass()741 JSHClass* GetReceiverHclass() const 742 { 743 ASSERT(receiverType_.IsJITClassType()); 744 return receiver_; 745 } GetHolderHclass()746 JSHClass* GetHolderHclass() const 747 { 748 ASSERT(receiverType_.IsJITClassType()); 749 return holder_; 750 } GetHolderTraHclass()751 JSHClass* GetHolderTraHclass() const 752 { 753 ASSERT(receiverType_.IsJITClassType()); 754 return holdTra_; 755 } 756 757 private: 758 PGOProfileType receiverRootType_ { PGOProfileType() }; 759 PGOProfileType receiverType_ { PGOProfileType() }; 760 PGOProfileType holdRootType_ { PGOProfileType() }; 761 PGOProfileType holdType_ { PGOProfileType() }; 762 PGOProfileType holdTraRootType_ { PGOProfileType() }; 763 PGOProfileType holdTraType_ { PGOProfileType() }; 764 JSHClass* receiver_ {nullptr}; 765 JSHClass* holder_ {nullptr}; 766 JSHClass *holdTra_ {nullptr}; 767 PGOSampleType accessorMethod_ { PGOSampleType() }; 768 ProtoChainMarker protoChainMarker_ {ProtoChainMarker::NOT_EXSIT}; 769 PGOProtoChainTemplate<PGOProfileType> *protoChain_ { nullptr }; 770 }; 771 using PGOObjectInfo = PGOObjectTemplate<ProfileType, PGOSampleType>; 772 using PGOObjectInfoRef = PGOObjectTemplate<ProfileTypeRef, PGOSampleTypeRef>; 773 774 template <typename PGOObjectInfoType> 775 class PGORWOpTemplate : public PGOType { 776 public: PGORWOpTemplate()777 PGORWOpTemplate() : PGOType(TypeKind::RW_OP_TYPE) {}; 778 779 template <typename FromType> ConvertFrom(PGOContext & context,const FromType & from)780 void ConvertFrom(PGOContext &context, const FromType &from) 781 { 782 count_ = std::min(from.GetCount(), static_cast<uint32_t>(POLY_CASE_NUM)); 783 for (uint32_t index = 0; index < count_; index++) { 784 infos_[index].ConvertFrom(context, from.GetObjectInfo(index)); 785 } 786 } 787 Merge(const PGORWOpTemplate & type)788 void Merge(const PGORWOpTemplate &type) 789 { 790 for (uint32_t i = 0; i < type.count_; i++) { 791 AddObjectInfo(type.infos_[i]); 792 } 793 } 794 AddObjectInfo(const PGOObjectInfoType & info)795 void AddObjectInfo(const PGOObjectInfoType &info) 796 { 797 if (info.IsNone()) { 798 return; 799 } 800 if (info.IsMegaStateType()) { 801 count_ = 1; 802 infos_[0] = info; 803 return; 804 } 805 uint32_t count = 0; 806 for (; count < count_; count++) { 807 if (infos_[count] == info) { 808 return; 809 } 810 } 811 if (count < static_cast<uint32_t>(POLY_CASE_NUM)) { 812 infos_[count] = info; 813 count_++; 814 } else { 815 LOG_ECMA(DEBUG) << "Class type exceeds 4, discard"; 816 } 817 } 818 GetObjectInfo(uint32_t index)819 const PGOObjectInfoType &GetObjectInfo(uint32_t index) const 820 { 821 ASSERT(index < count_); 822 return infos_[index]; 823 } 824 GetCount()825 uint32_t GetCount() const 826 { 827 return count_; 828 } 829 830 private: 831 static constexpr int POLY_CASE_NUM = 4; 832 uint32_t count_ = 0; 833 PGOObjectInfoType infos_[POLY_CASE_NUM]; 834 }; 835 using PGORWOpType = PGORWOpTemplate<PGOObjectInfo>; 836 using PGORWOpTypeRef = PGORWOpTemplate<PGOObjectInfoRef>; 837 838 template <typename PGOProfileType> 839 class PGODefineOpTemplate : public PGOType { 840 public: PGODefineOpTemplate()841 PGODefineOpTemplate() : PGOType(TypeKind::DEFINE_OP_TYPE), type_(PGOProfileType()) {}; PGODefineOpTemplate(PGOProfileType type)842 explicit PGODefineOpTemplate(PGOProfileType type) : PGOType(TypeKind::DEFINE_OP_TYPE), type_(type) {}; PGODefineOpTemplate(PGOProfileType type,JSHClass * hclass)843 explicit PGODefineOpTemplate(PGOProfileType type, JSHClass* hclass) : PGOType(TypeKind::DEFINE_OP_TYPE), 844 type_(type), receiver_(hclass) {}; 845 846 template <typename FromType> ConvertFrom(PGOContext & context,const FromType & from)847 void ConvertFrom(PGOContext &context, const FromType &from) 848 { 849 type_ = PGOProfileType(context, from.GetProfileType()); 850 ctorPt_ = PGOProfileType(context, from.GetCtorPt()); 851 protoPt_ = PGOProfileType(context, from.GetProtoTypePt()); 852 kind_ = from.GetElementsKind(); 853 elementsLength_ = from.GetElementsLength(); 854 spaceFlag_ = from.GetSpaceFlag(); 855 } 856 GetTypeString()857 std::string GetTypeString() const 858 { 859 std::string result = "(local"; 860 result += type_.GetTypeString(); 861 result += ", ctor"; 862 result += ctorPt_.GetTypeString(); 863 result += ", proto"; 864 result += protoPt_.GetTypeString(); 865 result += ", elementsKind:"; 866 result += std::to_string(static_cast<int32_t>(kind_)); 867 if (elementsLength_ > 0 && spaceFlag_ != RegionSpaceFlag::UNINITIALIZED) { 868 result += ", size: "; 869 result += std::to_string(elementsLength_); 870 result += ", space; "; 871 result += ToSpaceTypeName(spaceFlag_); 872 } 873 return result; 874 } 875 876 template <typename T> AddTypeJson(const char * typeName,const T & type,std::string typeOffset,std::vector<ProfileType::StringMap> & sameOffsetTypeArray)877 void AddTypeJson(const char *typeName, const T& type, std::string typeOffset, 878 std::vector<ProfileType::StringMap> &sameOffsetTypeArray) const 879 { 880 ProfileType::StringMap typeJson; 881 typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeName)); 882 typeJson.insert(std::make_pair(DumpJsonUtils::TYPE_NAME, typeOffset)); 883 type.GetTypeJson(typeJson); 884 sameOffsetTypeArray.push_back(typeJson); 885 } 886 GetTypeJson(std::vector<ProfileType::StringMap> & sameOffsetTypeArray,std::string typeOffset)887 void GetTypeJson(std::vector<ProfileType::StringMap> &sameOffsetTypeArray, 888 std::string typeOffset) const 889 { 890 AddTypeJson("localType", type_, typeOffset, sameOffsetTypeArray); 891 AddTypeJson("ctorType", ctorPt_, typeOffset, sameOffsetTypeArray); 892 AddTypeJson("protoType", protoPt_, typeOffset, sameOffsetTypeArray); 893 } 894 IsNone()895 bool IsNone() const 896 { 897 return type_.IsNone(); 898 } 899 GetProfileType()900 PGOProfileType GetProfileType() const 901 { 902 return type_; 903 } 904 SetCtorPt(PGOProfileType type)905 void SetCtorPt(PGOProfileType type) 906 { 907 ctorPt_ = type; 908 } 909 GetCtorPt()910 PGOProfileType GetCtorPt() const 911 { 912 return ctorPt_; 913 } 914 SetProtoTypePt(PGOProfileType type)915 void SetProtoTypePt(PGOProfileType type) 916 { 917 protoPt_ = type; 918 } 919 GetProtoTypePt()920 PGOProfileType GetProtoTypePt() const 921 { 922 return protoPt_; 923 } 924 SetElementsKind(ElementsKind kind)925 void SetElementsKind(ElementsKind kind) 926 { 927 kind_ = kind; 928 } 929 GetElementsKind()930 ElementsKind GetElementsKind() const 931 { 932 return kind_; 933 } 934 SetElementsLength(uint32_t length)935 void SetElementsLength(uint32_t length) 936 { 937 elementsLength_ = length; 938 } 939 GetElementsLength()940 uint32_t GetElementsLength() const 941 { 942 return elementsLength_; 943 } 944 SetSpaceFlag(RegionSpaceFlag flag)945 void SetSpaceFlag(RegionSpaceFlag flag) 946 { 947 spaceFlag_ = flag; 948 } 949 GetSpaceFlag()950 RegionSpaceFlag GetSpaceFlag() const 951 { 952 return spaceFlag_; 953 } 954 955 bool operator<(const PGODefineOpTemplate &right) const 956 { 957 return this->GetProfileType() < right.GetProfileType(); 958 } 959 GetReceiver()960 JSHClass* GetReceiver() const 961 { 962 ASSERT(type_.IsJITClassType()); 963 return receiver_; 964 } 965 966 private: 967 PGOProfileType type_ { PGOProfileType() }; 968 PGOProfileType ctorPt_ { PGOProfileType() }; 969 PGOProfileType protoPt_ { PGOProfileType() }; 970 uint32_t elementsLength_ { 0 }; 971 ElementsKind kind_ { ElementsKind::NONE }; 972 RegionSpaceFlag spaceFlag_ { RegionSpaceFlag::UNINITIALIZED }; 973 JSHClass* receiver_ {nullptr}; 974 }; 975 976 using PGODefineOpType = PGODefineOpTemplate<ProfileType>; 977 using PGODefineOpTypeRef = PGODefineOpTemplate<ProfileTypeRef>; 978 979 template <typename PGOProfileType> 980 class PGOProtoTransitionTemplate : public PGOType { 981 public: PGOProtoTransitionTemplate()982 PGOProtoTransitionTemplate() : PGOType(TypeKind::PROTO_TRANSITION_TYPE), ihcType_(PGOProfileType()) {}; PGOProtoTransitionTemplate(PGOProfileType type)983 explicit PGOProtoTransitionTemplate(PGOProfileType type) : PGOType(TypeKind::PROTO_TRANSITION_TYPE), 984 ihcType_(type) {} 985 986 template <typename FromType> ConvertFrom(PGOContext & context,const FromType & from)987 void ConvertFrom(PGOContext &context, const FromType &from) 988 { 989 ihcType_ = PGOProfileType(context, from.GetIhcType()); 990 baseRootPt_ = PGOProfileType(context, from.GetBaseType().first); 991 basePt_ = PGOProfileType(context, from.GetBaseType().second); 992 transIhcType_ = PGOProfileType(context, from.GetTransitionType()); 993 transProtoPt_ = PGOProfileType(context, from.GetTransitionProtoPt()); 994 } 995 GetTypeString()996 std::string GetTypeString() const 997 { 998 std::string result = "(ihc"; 999 result += ihcType_.GetTypeString(); 1000 result += ", baseRoot"; 1001 result += baseRootPt_.GetTypeString(); 1002 result += ", base"; 1003 result += basePt_.GetTypeString(); 1004 result += ", transIhc"; 1005 result += transIhcType_.GetTypeString(); 1006 result += ", transProto"; 1007 result += transProtoPt_.GetTypeString(); 1008 result += ")"; 1009 return result; 1010 } 1011 IsNone()1012 bool IsNone() const 1013 { 1014 return ihcType_.IsNone() || transIhcType_.IsNone(); 1015 } 1016 IsProtoTransitionNone()1017 bool IsProtoTransitionNone() const 1018 { 1019 return transIhcType_.IsNone(); 1020 } 1021 GetIhcType()1022 PGOProfileType GetIhcType() const 1023 { 1024 return ihcType_; 1025 } 1026 SetBaseType(PGOProfileType rootType,PGOProfileType type)1027 void SetBaseType(PGOProfileType rootType, PGOProfileType type) 1028 { 1029 baseRootPt_ = rootType; 1030 basePt_ = type; 1031 } 1032 GetBaseType()1033 std::pair<PGOProfileType, PGOProfileType> GetBaseType() const 1034 { 1035 return std::make_pair(baseRootPt_, basePt_); 1036 } 1037 SetTransitionType(PGOProfileType type)1038 void SetTransitionType(PGOProfileType type) 1039 { 1040 transIhcType_ = type; 1041 } 1042 GetTransitionType()1043 PGOProfileType GetTransitionType() const 1044 { 1045 return transIhcType_; 1046 } 1047 SetTransitionProtoPt(PGOProfileType type)1048 void SetTransitionProtoPt(PGOProfileType type) 1049 { 1050 transProtoPt_ = type; 1051 } 1052 GetTransitionProtoPt()1053 PGOProfileType GetTransitionProtoPt() const 1054 { 1055 return transProtoPt_; 1056 } 1057 1058 bool operator<(const PGOProtoTransitionTemplate &right) const 1059 { 1060 return this->GetIhcType() < right.GetIhcType(); 1061 } 1062 IsSameProtoTransition(const PGOProtoTransitionTemplate & type)1063 bool IsSameProtoTransition(const PGOProtoTransitionTemplate &type) const 1064 { 1065 return (GetBaseType().first == type.GetBaseType().first) && 1066 (GetBaseType().second == type.GetBaseType().second) && 1067 (GetTransitionType() == type.GetTransitionType()) && 1068 (GetTransitionProtoPt() == type.GetTransitionProtoPt()); 1069 } 1070 1071 // only support mono-state prototype transition now CombineType(const PGOProtoTransitionTemplate & type)1072 PGOProtoTransitionTemplate CombineType(const PGOProtoTransitionTemplate &type) 1073 { 1074 ASSERT(GetIhcType() == type.GetIhcType()); 1075 if (IsProtoTransitionNone() || IsSameProtoTransition(type)) { 1076 return *this; 1077 } 1078 // clear all except for key 1079 SetBaseType(PGOProfileType(), PGOProfileType()); 1080 SetTransitionType(PGOProfileType()); 1081 SetTransitionProtoPt(PGOProfileType()); 1082 return *this; 1083 } 1084 1085 private: 1086 PGOProfileType ihcType_ { PGOProfileType() }; // key 1087 PGOProfileType baseRootPt_ { PGOProfileType() }; 1088 PGOProfileType basePt_ { PGOProfileType() }; 1089 PGOProfileType transIhcType_ { PGOProfileType() }; 1090 PGOProfileType transProtoPt_ { PGOProfileType() }; 1091 }; 1092 using PGOProtoTransitionType = PGOProtoTransitionTemplate<ProfileType>; 1093 using PGOProtoTransitionTypeRef = PGOProtoTransitionTemplate<ProfileTypeRef>; 1094 1095 class PGOTypeRef { 1096 public: PGOTypeRef()1097 PGOTypeRef() : type_(nullptr) {} 1098 PGOTypeRef(PGOType * type)1099 explicit PGOTypeRef(PGOType *type) : type_(type) {} 1100 PGOTypeRef(const PGOSampleType * type)1101 explicit PGOTypeRef(const PGOSampleType *type) : type_(static_cast<const PGOType*>(type)) {} 1102 PGOTypeRef(const PGORWOpType * type)1103 explicit PGOTypeRef(const PGORWOpType *type) : type_(static_cast<const PGOType*>(type)) {} 1104 PGOTypeRef(const PGODefineOpType * type)1105 explicit PGOTypeRef(const PGODefineOpType *type) : type_(static_cast<const PGOType*>(type)) {} 1106 PGOTypeRef(const PGOProtoTransitionType * type)1107 explicit PGOTypeRef(const PGOProtoTransitionType *type) : type_(static_cast<const PGOType*>(type)) {} 1108 NoneType()1109 static PGOTypeRef NoneType() 1110 { 1111 return PGOTypeRef(); 1112 } 1113 1114 bool operator<(const PGOTypeRef &right) const 1115 { 1116 return type_ < right.type_; 1117 } 1118 1119 bool operator!=(const PGOTypeRef &right) const 1120 { 1121 return type_ != right.type_; 1122 } 1123 1124 bool operator==(const PGOTypeRef &right) const 1125 { 1126 return type_ == right.type_; 1127 } 1128 IsValid()1129 bool IsValid() const 1130 { 1131 return type_ != nullptr; 1132 } 1133 IsValidCallMethodId()1134 bool IsValidCallMethodId() const 1135 { 1136 if (type_ == nullptr) { 1137 return false; 1138 } 1139 if (!type_->IsScalarOpType()) { 1140 return false; 1141 } 1142 auto sampleType = static_cast<const PGOSampleType*>(type_); 1143 if (sampleType->IsProfileType()) { 1144 if (sampleType->GetProfileType().IsMethodId()) { 1145 return sampleType->GetProfileType().IsValidCallMethodId(); 1146 } 1147 if (sampleType->GetProfileType().IsClassType()) { 1148 return sampleType->GetProfileType().IsValidClassConstructorMethodId(); 1149 } 1150 } 1151 return false; 1152 } 1153 IsDefOpValidCallMethodId()1154 bool IsDefOpValidCallMethodId() const 1155 { 1156 if (type_ == nullptr) { 1157 return false; 1158 } 1159 if (!type_->IsDefineOpType()) { 1160 return false; 1161 } 1162 auto sampleType = static_cast<const PGODefineOpType*>(type_); 1163 if (sampleType->GetProfileType().IsMethodId()) { 1164 return sampleType->GetProfileType().IsValidCallMethodId(); 1165 } 1166 if (sampleType->GetProfileType().IsClassType()) { 1167 return sampleType->GetProfileType().IsValidClassConstructorMethodId(); 1168 } 1169 return false; 1170 } 1171 GetCallMethodId()1172 uint32_t GetCallMethodId() const 1173 { 1174 auto sampleType = static_cast<const PGOSampleType*>(type_); 1175 if (sampleType->GetProfileType().IsClassType()) { 1176 return sampleType->GetProfileType().GetClassConstructorMethodId(); 1177 } 1178 return sampleType->GetProfileType().GetCallMethodId(); 1179 } 1180 GetDefOpCallMethodId()1181 uint32_t GetDefOpCallMethodId() const 1182 { 1183 auto sampleType = static_cast<const PGODefineOpType*>(type_); 1184 if (sampleType->GetProfileType().IsClassType()) { 1185 return sampleType->GetProfileType().GetClassConstructorMethodId(); 1186 } 1187 return sampleType->GetProfileType().GetCallMethodId(); 1188 } 1189 GetValue()1190 uint64_t GetValue() const 1191 { 1192 auto sampleType = static_cast<const PGOSampleType*>(type_); 1193 return sampleType->GetProfileType().GetRaw(); 1194 } 1195 GetPGOSampleType()1196 const PGOSampleType* GetPGOSampleType() const 1197 { 1198 if (type_ == nullptr) { 1199 static PGOSampleType noneType = PGOSampleType::NoneType(); 1200 return &noneType; 1201 } 1202 ASSERT(type_->IsScalarOpType()); 1203 return static_cast<const PGOSampleType*>(type_); 1204 } 1205 IsPGOSampleType()1206 bool IsPGOSampleType() const 1207 { 1208 if (type_ == nullptr) { 1209 return false; 1210 } 1211 return type_->IsScalarOpType(); 1212 } 1213 HasNumber()1214 bool HasNumber() const 1215 { 1216 return GetPGOSampleType()->HasNumber(); 1217 } 1218 IsBoolean()1219 bool IsBoolean() const 1220 { 1221 return GetPGOSampleType()->IsBoolean(); 1222 } 1223 IsString()1224 bool IsString() const 1225 { 1226 return GetPGOSampleType()->IsString(); 1227 } 1228 IsHeapObject()1229 bool IsHeapObject() const 1230 { 1231 return GetPGOSampleType()->IsHeapObject(); 1232 } 1233 IsNumberOrString()1234 bool IsNumberOrString() const 1235 { 1236 return GetPGOSampleType()->IsNumberOrString(); 1237 } 1238 GetPGORWOpType()1239 const PGORWOpType* GetPGORWOpType() 1240 { 1241 if (type_ == nullptr) { 1242 static PGORWOpType noneType; 1243 return &noneType; 1244 } 1245 ASSERT(type_->IsRwOpType()); 1246 return static_cast<const PGORWOpType*>(type_); 1247 } 1248 GetPGODefineOpType()1249 const PGODefineOpType* GetPGODefineOpType() 1250 { 1251 if (type_ == nullptr) { 1252 static PGODefineOpType noneType; 1253 return &noneType; 1254 } 1255 ASSERT(type_->IsDefineOpType()); 1256 return static_cast<const PGODefineOpType*>(type_); 1257 } 1258 1259 private: 1260 const PGOType *type_; 1261 }; 1262 } // namespace panda::ecmascript::pgo 1263 #endif // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_PROFILER_TYPE_H 1264