1/* 2 * Copyright (c) 2023-2024 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_LAYOUT_H 17#define ECMASCRIPT_PGO_PROFILER_LAYOUT_H 18 19#include <cstdint> 20#include <string> 21 22#include "ecmascript/ecma_vm.h" 23#include "ecmascript/elements.h" 24#include "ecmascript/js_hclass.h" 25#include "ecmascript/js_object.h" 26#include "ecmascript/log_wrapper.h" 27#include "ecmascript/mem/c_containers.h" 28#include "ecmascript/mem/region.h" 29#include "ecmascript/pgo_profiler/pgo_context.h" 30#include "ecmascript/pgo_profiler/pgo_utils.h" 31#include "ecmascript/pgo_profiler/types/pgo_profile_type.h" 32#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h" 33#include "ecmascript/property_attributes.h" 34 35namespace panda::ecmascript::pgo { 36class PGOHandler { 37public: 38 using TrackTypeField = 39 PropertyAttributes::PropertyMetaDataField::NextField<TrackType, PropertyAttributes::TRACK_TYPE_NUM>; 40 using IsSymbol = TrackTypeField::NextFlag; 41 42 PGOHandler() 43 { 44 SetTrackType(TrackType::NONE); 45 SetPropertyMeta(false); 46 } 47 48 PGOHandler(TrackType type, int meta) 49 { 50 SetTrackType(type); 51 SetPropertyMeta(meta); 52 } 53 54 PGOHandler(TrackType type, int meta, bool isSymbol) 55 { 56 SetTrackType(type); 57 SetPropertyMeta(meta); 58 SetIsSymbol(isSymbol); 59 } 60 61 uint32_t GetValue() const 62 { 63 return value_; 64 } 65 66 bool SetAttribute(const JSThread *thread, PropertyAttributes &attr) const; 67 68 void SetIsSymbol(bool isSymbol) 69 { 70 IsSymbol::Set(isSymbol, &value_); 71 } 72 73 bool GetIsSymbol() const 74 { 75 return IsSymbol::Get(value_); 76 } 77 78 void SetTrackType(TrackType type) 79 { 80 TrackTypeField::Set(type, &value_); 81 } 82 83 TrackType GetTrackType() const 84 { 85 return TrackTypeField::Get(value_); 86 } 87 88 void SetPropertyMeta(int meta) 89 { 90 PropertyAttributes::PropertyMetaDataField::Set(meta, &value_); 91 } 92 93 int GetPropertyMeta() const 94 { 95 return PropertyAttributes::PropertyMetaDataField::Get(value_); 96 } 97 98 bool IsAccessor() const 99 { 100 return PropertyAttributes::IsAccessorField::Get(value_); 101 } 102 103 bool IsWritable() const 104 { 105 return PropertyAttributes::WritableField::Get(value_); 106 } 107 108 bool IsEnumerable() const 109 { 110 return PropertyAttributes::EnumerableField::Get(value_); 111 } 112 113 bool IsConfigurable() const 114 { 115 return PropertyAttributes::ConfigurableField::Get(value_); 116 } 117 118 bool operator!=(const PGOHandler &right) const 119 { 120 return value_ != right.value_; 121 } 122 123 bool operator==(const PGOHandler &right) const 124 { 125 return value_ == right.value_; 126 } 127 128private: 129 uint32_t value_ { 0 }; 130}; 131 132using PropertyDesc = std::pair<CString, PGOHandler>; 133using LayoutDesc = CVector<PropertyDesc>; 134class PGOHClassTreeDesc; 135 136class HClassLayoutDesc { 137public: 138 explicit HClassLayoutDesc(ProfileType type) : type_(type) {} 139 HClassLayoutDesc(ProfileType type, const CSet<ProfileType> &childs) : type_(type), childs_(childs) {} 140 virtual ~HClassLayoutDesc() = default; 141 142 virtual void Merge(const HClassLayoutDesc *from); 143 virtual void InsertKeyAndDesc(const CString &key, const PGOHandler &handler) = 0; 144 virtual bool UpdateKeyAndDesc(const CString &key, const PGOHandler &handler) = 0; 145 146 ProfileType GetProfileType() const 147 { 148 return type_; 149 } 150 151 void AddChildHClassLayoutDesc(const ProfileType &type) 152 { 153 if (type_.GetRaw() == type.GetRaw()) { 154 return; 155 } 156 childs_.emplace(type); 157 } 158 159 bool FindChild(const ProfileType &type) 160 { 161 return childs_.find(type) != childs_.end(); 162 } 163 164 inline size_t GetChildSize() const 165 { 166 return childs_.size(); 167 } 168 169 template<typename Callback> 170 void IterateChilds(Callback callback) const 171 { 172 for (const auto &type : childs_) { 173 if (!callback(type)) { 174 break; 175 } 176 } 177 } 178 179protected: 180 void InsertKeyAndDesc(const PGOHandler &handler, PropertyDesc &desc); 181 182 ProfileType type_; 183 CSet<ProfileType> childs_; 184}; 185 186class RootHClassLayoutDesc final : public HClassLayoutDesc { 187public: 188 explicit RootHClassLayoutDesc(ProfileType type) : HClassLayoutDesc(type) {} 189 RootHClassLayoutDesc(ProfileType type, JSType objType, uint32_t objSize) 190 : HClassLayoutDesc(type), objType_(objType), objSize_(objSize) {} 191 RootHClassLayoutDesc(const RootHClassLayoutDesc &desc) 192 : HClassLayoutDesc(desc.type_, desc.childs_), objType_(desc.objType_), objSize_(desc.objSize_), 193 layoutDesc_(desc.layoutDesc_) {} 194 RootHClassLayoutDesc& operator=(const RootHClassLayoutDesc &desc) 195 { 196 this->type_ = desc.type_; 197 this->childs_ = desc.childs_; 198 this->objType_ = desc.objType_; 199 this->objSize_ = desc.objSize_; 200 this->layoutDesc_ = desc.layoutDesc_; 201 return *this; 202 } 203 204 void Merge(const HClassLayoutDesc *from) override; 205 void InsertKeyAndDesc(const CString &key, const PGOHandler &handler) override; 206 bool UpdateKeyAndDesc(const CString &key, const PGOHandler &handler) override; 207 208 void SetObjectSize(uint32_t objSize) 209 { 210 objSize_ = objSize; 211 } 212 213 uint32_t GetObjectSize() const 214 { 215 return objSize_; 216 } 217 218 void SetObjectType(JSType objType) 219 { 220 objType_ = objType; 221 } 222 223 JSType GetObjectType() const 224 { 225 return objType_; 226 } 227 228 size_t NumOfProps() const 229 { 230 return layoutDesc_.size(); 231 } 232 233 template<typename Callback> 234 void IterateProps(Callback callback) const 235 { 236 for (const auto &iter : layoutDesc_) { 237 callback(iter); 238 } 239 } 240 241private: 242 JSType objType_; 243 uint32_t objSize_ {0}; 244 LayoutDesc layoutDesc_; 245}; 246 247class ChildHClassLayoutDesc final : public HClassLayoutDesc { 248public: 249 explicit ChildHClassLayoutDesc(ProfileType type) : HClassLayoutDesc(type) {} 250 ChildHClassLayoutDesc(const ChildHClassLayoutDesc &desc) 251 : HClassLayoutDesc(desc.type_, desc.childs_), propertyDesc_(desc.propertyDesc_) {} 252 ChildHClassLayoutDesc& operator=(const ChildHClassLayoutDesc &desc) 253 { 254 this->type_ = desc.type_; 255 this->childs_ = desc.childs_; 256 this->propertyDesc_ = desc.propertyDesc_; 257 return *this; 258 } 259 260 void Merge(const HClassLayoutDesc *from) override; 261 void InsertKeyAndDesc(const CString &key, const PGOHandler &handler) override; 262 bool UpdateKeyAndDesc(const CString &key, const PGOHandler &handler) override; 263 264 PropertyDesc GetPropertyDesc() const 265 { 266 return propertyDesc_; 267 } 268 269private: 270 PropertyDesc propertyDesc_; 271}; 272 273class PGOHClassTreeDesc { 274public: 275 PGOHClassTreeDesc() = default; 276 explicit PGOHClassTreeDesc(ProfileType type) : type_(type) {} 277 278 void Clear(); 279 280 ProfileType GetProfileType() const 281 { 282 return type_; 283 } 284 285 void SetProtoPt(ProfileType protoPt) 286 { 287 protoPt_ = protoPt; 288 } 289 290 ProfileType GetProtoPt() const 291 { 292 return protoPt_; 293 } 294 295 void Merge(const PGOHClassTreeDesc &from); 296 297 bool operator<(const PGOHClassTreeDesc &right) const 298 { 299 return type_ < right.type_; 300 } 301 302 HClassLayoutDesc *GetHClassLayoutDesc(ProfileType type) const; 303 HClassLayoutDesc *GetOrInsertHClassLayoutDesc(ProfileType type, bool root = false); 304 305 bool DumpForRoot(JSTaggedType root, ProfileType rootType); 306 bool DumpForChild(JSTaggedType child, ProfileType childType); 307 bool UpdateForTransition(JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType); 308 bool UpdateLayout(JSTaggedType curHClass, ProfileType curType); 309 bool IsDumped(ProfileType curType) const; 310 311 template<typename Callback> 312 void IterateChilds(Callback callback) const 313 { 314 IterateAll([&callback] (HClassLayoutDesc *desc) { 315 if (desc->GetProfileType().IsRootType()) { 316 return; 317 } 318 callback(reinterpret_cast<ChildHClassLayoutDesc *>(desc)); 319 }); 320 } 321 322private: 323 template<typename Callback> 324 void IterateAll(Callback callback) const 325 { 326 for (auto iter : transitionLayout_) { 327 callback(iter.second); 328 } 329 } 330 331 ProfileType type_; 332 ProfileType protoPt_; 333 CMap<ProfileType, HClassLayoutDesc *> transitionLayout_; 334}; 335 336class PGOLayoutDescInfo { 337public: 338 PGOLayoutDescInfo() = default; 339 PGOLayoutDescInfo(const CString &key, PGOHandler handler) : handler_(handler) 340 { 341 size_t len = key.size(); 342 size_ = Size(len); 343 if (len > 0 && memcpy_s(&key_, len, key.c_str(), len) != EOK) { 344 LOG_ECMA(ERROR) << "SetMethodName memcpy_s failed" << key << ", len = " << len; 345 UNREACHABLE(); 346 } 347 *(&key_ + len) = '\0'; 348 } 349 350 static int32_t Size(size_t len) 351 { 352 return sizeof(PGOLayoutDescInfo) + AlignUp(len, GetAlignmentInBytes(ALIGN_SIZE)); 353 } 354 355 int32_t Size() const 356 { 357 return size_; 358 } 359 360 const char *GetKey() const 361 { 362 return &key_; 363 } 364 365 PGOHandler GetHandler() const 366 { 367 return handler_; 368 } 369 370private: 371 int32_t size_ {0}; 372 PGOHandler handler_; 373 char key_ {'\0'}; 374}; 375 376class HClassLayoutDescInner { 377public: 378 virtual ~HClassLayoutDescInner() = default; 379 int32_t Size() const 380 { 381 return size_; 382 } 383 384 ProfileType GetProfileType() const 385 { 386 return type_; 387 } 388 389protected: 390 int32_t size_ { 0 }; 391 ProfileType type_; 392}; 393 394class RootHClassLayoutDescInner : public HClassLayoutDescInner { 395public: 396 static size_t CaculateSize(const RootHClassLayoutDesc &desc) 397 { 398 size_t size = sizeof(RootHClassLayoutDescInner); 399 size += desc.GetChildSize() * sizeof(ProfileType); 400 desc.IterateProps([&size] (const PropertyDesc &propDesc) { 401 auto key = propDesc.first; 402 size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size())); 403 }); 404 return size; 405 } 406 407 void Merge(const RootHClassLayoutDesc &desc) 408 { 409 size_ = static_cast<int32_t>(RootHClassLayoutDescInner::CaculateSize(desc)); 410 type_ = desc.GetProfileType(); 411 childCount_ = 0; 412 desc.IterateChilds([this] (const ProfileType &childType) -> bool { 413 auto newChildType = const_cast<ProfileType *>(GetChildType(childCount_++)); 414 new (newChildType) ProfileType(childType); 415 return true; 416 }); 417 418 auto current = const_cast<PGOLayoutDescInfo *>(GetFirstProperty()); 419 desc.IterateProps([this, ¤t] (const PropertyDesc &propDesc) { 420 auto key = propDesc.first; 421 auto type = propDesc.second; 422 new (current) PGOLayoutDescInfo(key, type); 423 current = const_cast<PGOLayoutDescInfo *>(GetNextProperty(current)); 424 propCount_++; 425 }); 426 } 427 428 void Convert(PGOContext& context, RootHClassLayoutDesc *desc) const 429 { 430 auto descInfo = GetFirstProperty(); 431 for (uint32_t i = 0; i < propCount_; i++) { 432 desc->InsertKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler()); 433 descInfo = GetNextProperty(descInfo); 434 } 435 for (uint32_t i = 0; i < childCount_; i++) { 436 auto profileType(*GetChildType(i)); 437 desc->AddChildHClassLayoutDesc(profileType.Remap(context)); 438 } 439 } 440 441 void SetObjectType(JSType objType) 442 { 443 objType_ = objType; 444 } 445 446 JSType GetObjectType() const 447 { 448 return objType_; 449 } 450 451 void SetObjectSize(uint32_t size) 452 { 453 objSize_ = size; 454 } 455 456 uint32_t GetObjectSize() const 457 { 458 return objSize_; 459 } 460 461private: 462 const ProfileType *GetChildType(uint32_t index) const 463 { 464 return (&childType_) + index; 465 } 466 467 const PGOLayoutDescInfo *GetFirstProperty() const 468 { 469 return reinterpret_cast<const PGOLayoutDescInfo *>(reinterpret_cast<uintptr_t>(&childType_ + childCount_)); 470 } 471 472 const PGOLayoutDescInfo *GetNextProperty(const PGOLayoutDescInfo *current) const 473 { 474 return reinterpret_cast<const PGOLayoutDescInfo *>(reinterpret_cast<uintptr_t>(current) + current->Size()); 475 } 476 477 JSType objType_; 478 uint32_t objSize_ {0}; 479 uint32_t propCount_ {0}; 480 uint32_t childCount_ {0}; 481 ProfileType childType_; 482}; 483 484class ChildHClassLayoutDescInner : public HClassLayoutDescInner { 485public: 486 static size_t CaculateSize(const ChildHClassLayoutDesc &desc) 487 { 488 size_t size = sizeof(ChildHClassLayoutDescInner); 489 size += desc.GetChildSize() * sizeof(ProfileType); 490 auto key = desc.GetPropertyDesc().first; 491 size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size())); 492 return size; 493 } 494 495 void Merge(const ChildHClassLayoutDesc &desc) 496 { 497 size_ = static_cast<int32_t>(ChildHClassLayoutDescInner::CaculateSize(desc)); 498 type_ = desc.GetProfileType(); 499 childCount_ = 0; 500 desc.IterateChilds([this] (const ProfileType &childType) -> bool { 501 auto newChildType = const_cast<ProfileType *>(GetChildType(childCount_++)); 502 new (newChildType) ProfileType(childType); 503 return true; 504 }); 505 506 auto current = const_cast<PGOLayoutDescInfo *>(GetProperty()); 507 auto propDesc = desc.GetPropertyDesc(); 508 auto key = propDesc.first; 509 auto type = propDesc.second; 510 new (current) PGOLayoutDescInfo(key, type); 511 } 512 513 void Convert(PGOContext& context, ChildHClassLayoutDesc *desc) const 514 { 515 auto descInfo = GetProperty(); 516 desc->InsertKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler()); 517 for (uint32_t i = 0; i < childCount_; i++) { 518 auto profileType(*GetChildType(i)); 519 desc->AddChildHClassLayoutDesc(profileType.Remap(context)); 520 } 521 } 522 523private: 524 const ProfileType *GetChildType(uint32_t index) const 525 { 526 return (&childType_) + index; 527 } 528 529 const PGOLayoutDescInfo *GetProperty() const 530 { 531 return reinterpret_cast<const PGOLayoutDescInfo *>(&childType_ + childCount_); 532 } 533 534 uint32_t childCount_ { 0 }; 535 ProfileType childType_; 536}; 537 538template <typename SampleType> 539class PGOHClassTreeTemplate { 540public: 541 PGOHClassTreeTemplate(size_t size, SampleType type, SampleType protoSt) 542 : size_(size), type_(type), protoSt_(protoSt) {} 543 544 static size_t CaculateSize(const PGOHClassTreeDesc &desc) 545 { 546 auto rootLayout = desc.GetHClassLayoutDesc(desc.GetProfileType()); 547 if (rootLayout == nullptr) { 548 return sizeof(PGOHClassTreeTemplate<SampleType>); 549 } 550 size_t size = sizeof(PGOHClassTreeTemplate<SampleType>) - sizeof(RootHClassLayoutDescInner); 551 size += RootHClassLayoutDescInner::CaculateSize(*reinterpret_cast<const RootHClassLayoutDesc *>(rootLayout)); 552 553 desc.IterateChilds([&size](ChildHClassLayoutDesc *desc) { 554 size += ChildHClassLayoutDescInner::CaculateSize(*desc); 555 }); 556 return size; 557 } 558 559 static std::string GetTypeString(const PGOHClassTreeDesc &desc) 560 { 561 std::string text; 562 text += desc.GetProfileType().GetTypeString(); 563 text += DumpUtils::BLOCK_AND_ARRAY_START; 564 auto layoutDesc = desc.GetHClassLayoutDesc(desc.GetProfileType()); 565 if (layoutDesc != nullptr) { 566 bool isLayoutFirst = true; 567 ASSERT(layoutDesc->GetProfileType().IsRootType()); 568 auto rootLayoutDesc = reinterpret_cast<RootHClassLayoutDesc *>(layoutDesc); 569 rootLayoutDesc->IterateProps([&text, &isLayoutFirst] (const PropertyDesc &propDesc) { 570 if (!isLayoutFirst) { 571 text += DumpUtils::TYPE_SEPARATOR + DumpUtils::SPACE; 572 } else { 573 text += DumpUtils::ARRAY_START; 574 } 575 isLayoutFirst = false; 576 text += propDesc.first; 577 text += DumpUtils::BLOCK_START; 578 text += std::to_string(propDesc.second.GetValue()); 579 }); 580 } 581 text += (DumpUtils::SPACE + DumpUtils::ARRAY_END); 582 return text; 583 } 584 585 void Merge(const PGOHClassTreeDesc &desc) 586 { 587 auto root = const_cast<RootHClassLayoutDescInner *>(GetRoot()); 588 auto layoutDesc = desc.GetHClassLayoutDesc(desc.GetProfileType()); 589 if (layoutDesc == nullptr) { 590 return; 591 } 592 auto rootLayoutDesc = reinterpret_cast<const RootHClassLayoutDesc *>(layoutDesc); 593 root->Merge(*rootLayoutDesc); 594 root->SetObjectType(rootLayoutDesc->GetObjectType()); 595 root->SetObjectSize(rootLayoutDesc->GetObjectSize()); 596 597 childCount_ = 0; 598 auto last = reinterpret_cast<HClassLayoutDescInner *>(root); 599 desc.IterateChilds([this, &last](ChildHClassLayoutDesc *desc) { 600 auto current = const_cast<ChildHClassLayoutDescInner *>(GetNext(last)); 601 new (current) ChildHClassLayoutDescInner(); 602 current->Merge(*desc); 603 last = current; 604 childCount_++; 605 }); 606 } 607 608 PGOHClassTreeDesc Convert(PGOContext& context) 609 { 610 PGOHClassTreeDesc desc(ProfileType(context, GetType().GetProfileType())); 611 desc.SetProtoPt(ProfileType(context, GetProtoSt().GetProfileType())); 612 auto root = GetRoot(); 613 if (root->GetProfileType().IsNone()) { 614 return desc; 615 } 616 auto layoutDesc = desc.GetOrInsertHClassLayoutDesc(root->GetProfileType().Remap(context), true); 617 auto rootLayoutDesc = reinterpret_cast<RootHClassLayoutDesc *>(layoutDesc); 618 rootLayoutDesc->SetObjectType(root->GetObjectType()); 619 rootLayoutDesc->SetObjectSize(root->GetObjectSize()); 620 root->Convert(context, rootLayoutDesc); 621 622 auto last = reinterpret_cast<const HClassLayoutDescInner *>(root); 623 for (int32_t i = 0; i < childCount_; i++) { 624 auto current = GetNext(last); 625 auto childLayoutDesc = desc.GetOrInsertHClassLayoutDesc(current->GetProfileType().Remap(context), false); 626 current->Convert(context, reinterpret_cast<ChildHClassLayoutDesc *>(childLayoutDesc)); 627 last = current; 628 } 629 return desc; 630 } 631 632 int32_t Size() const 633 { 634 return size_; 635 } 636 637 SampleType GetType() const 638 { 639 return type_; 640 } 641 642 SampleType GetProtoSt() const 643 { 644 return protoSt_; 645 } 646 647private: 648 const RootHClassLayoutDescInner *GetRoot() const 649 { 650 return &rootHClassLayout_; 651 } 652 653 const ChildHClassLayoutDescInner *GetNext(const HClassLayoutDescInner *current) const 654 { 655 return reinterpret_cast<const ChildHClassLayoutDescInner *>( 656 reinterpret_cast<uintptr_t>(current) + current->Size()); 657 } 658 659 uintptr_t GetEnd() const 660 { 661 return reinterpret_cast<uintptr_t>(this) + Size(); 662 } 663 664 int32_t size_; 665 SampleType type_; 666 SampleType protoSt_; 667 int32_t childCount_ { 0 }; 668 RootHClassLayoutDescInner rootHClassLayout_; 669}; 670 671using PGOHClassTreeDescInner = PGOHClassTreeTemplate<PGOSampleType>; 672using PGOHClassTreeDescInnerRef = PGOHClassTreeTemplate<PGOSampleTypeRef>; 673} // namespace panda::ecmascript::pgo 674#endif // ECMASCRIPT_PGO_PROFILER_LAYOUT_H 675