1 /** 2 * Copyright (c) 2021-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 #ifndef PANDA_RUNTIME_CLASS_H_ 16 #define PANDA_RUNTIME_CLASS_H_ 17 18 #include <securec.h> 19 #include <atomic> 20 #include <cstdint> 21 #include <iostream> 22 #include <memory> 23 24 #include "libpandafile/file.h" 25 #include "libpandafile/file_items.h" 26 #include "runtime/include/field.h" 27 #include "runtime/include/itable.h" 28 #include "runtime/include/method.h" 29 #include "libpandabase/macros.h" 30 31 namespace ark { 32 33 class ClassLinkerContext; 34 class ManagedThread; 35 class ObjectHeader; 36 37 // NOTE (Artem Udovichenko): move BaseClass to another file but still have Class.h 38 class BaseClass { 39 public: 40 static constexpr uint32_t DYNAMIC_CLASS = 1U; 41 42 public: BaseClass(panda_file::SourceLang lang)43 explicit BaseClass(panda_file::SourceLang lang) : lang_(lang) {} 44 45 ~BaseClass() = default; 46 47 DEFAULT_COPY_SEMANTIC(BaseClass); 48 DEFAULT_MOVE_SEMANTIC(BaseClass); 49 GetFlags()50 uint32_t GetFlags() const 51 { 52 return flags_; 53 } 54 IsDynamicClass()55 bool IsDynamicClass() const 56 { 57 return (flags_ & DYNAMIC_CLASS) != 0; 58 } 59 GetObjectSize()60 uint32_t GetObjectSize() const 61 { 62 return objectSize_; 63 } 64 SetObjectSize(uint32_t size)65 void SetObjectSize(uint32_t size) 66 { 67 objectSize_ = size; 68 } 69 SetManagedObject(ObjectHeader * obj)70 void SetManagedObject(ObjectHeader *obj) 71 { 72 managedObject_ = obj; 73 } 74 GetManagedObject()75 ObjectHeader *GetManagedObject() const 76 { 77 return managedObject_; 78 } 79 GetSourceLang()80 panda_file::SourceLang GetSourceLang() const 81 { 82 return lang_; 83 } 84 SetSourceLang(panda_file::SourceLang lang)85 void SetSourceLang(panda_file::SourceLang lang) 86 { 87 lang_ = lang; 88 } 89 GetFlagsOffset()90 static constexpr uint32_t GetFlagsOffset() 91 { 92 return MEMBER_OFFSET(BaseClass, flags_); 93 } GetManagedObjectOffset()94 static constexpr size_t GetManagedObjectOffset() 95 { 96 return MEMBER_OFFSET(BaseClass, managedObject_); 97 } GetObjectSizeOffset()98 static constexpr size_t GetObjectSizeOffset() 99 { 100 return MEMBER_OFFSET(BaseClass, objectSize_); 101 } 102 103 protected: SetFlags(uint32_t flags)104 void SetFlags(uint32_t flags) 105 { 106 flags_ = flags; 107 } 108 109 private: 110 uint32_t flags_ {0}; 111 // Size of the object of this class. In case of static classes it is 0 112 // for abstract classes, interfaces and classes whose objects 113 // have variable size (for example strings). 114 uint32_t objectSize_ {0}; 115 ObjectHeader *managedObject_ {nullptr}; 116 panda_file::SourceLang lang_; 117 }; 118 119 class Class : public BaseClass { 120 public: 121 using UniqId = uint64_t; 122 static constexpr uint32_t STRING_CLASS = DYNAMIC_CLASS << 1U; 123 static constexpr uint32_t IS_CLONEABLE = STRING_CLASS << 1U; 124 static constexpr size_t IMTABLE_SIZE = 32; 125 126 enum { 127 DUMPCLASSFULLDETAILS = 1, 128 DUMPCLASSCLASSLODER = 2, 129 DUMPCLASSINITIALIZED = 4, 130 }; 131 132 enum class State : uint8_t { INITIAL = 0, LOADED, VERIFIED, INITIALIZING, ERRONEOUS, INITIALIZED }; 133 134 Class(const uint8_t *descriptor, panda_file::SourceLang lang, uint32_t vtableSize, uint32_t imtSize, uint32_t size); 135 GetBase()136 Class *GetBase() const 137 { 138 return base_; 139 } 140 SetBase(Class * base)141 void SetBase(Class *base) 142 { 143 base_ = base; 144 } 145 GetFileId()146 panda_file::File::EntityId GetFileId() const 147 { 148 return fileId_; 149 } 150 SetFileId(panda_file::File::EntityId fileId)151 void SetFileId(panda_file::File::EntityId fileId) 152 { 153 fileId_ = fileId; 154 } 155 GetPandaFile()156 const panda_file::File *GetPandaFile() const 157 { 158 return pandaFile_; 159 } 160 SetPandaFile(const panda_file::File * pf)161 void SetPandaFile(const panda_file::File *pf) 162 { 163 pandaFile_ = pf; 164 } 165 GetDescriptor()166 const uint8_t *GetDescriptor() const 167 { 168 return descriptor_; 169 } 170 SetMethods(Span<Method> methods,uint32_t numVmethods,uint32_t numSmethods)171 void SetMethods(Span<Method> methods, uint32_t numVmethods, uint32_t numSmethods) 172 { 173 methods_ = methods.data(); 174 numMethods_ = numVmethods + numSmethods; 175 numVmethods_ = numVmethods; 176 numCopiedMethods_ = methods.size() - numMethods_; 177 } 178 GetRawFirstMethodAddr()179 Method *GetRawFirstMethodAddr() const 180 { 181 return methods_; 182 } 183 GetMethods()184 Span<Method> GetMethods() const 185 { 186 return {methods_, numMethods_}; 187 } 188 GetMethodsWithCopied()189 Span<Method> GetMethodsWithCopied() const 190 { 191 return {methods_, numMethods_ + numCopiedMethods_}; 192 } 193 GetStaticMethods()194 Span<Method> GetStaticMethods() const 195 { 196 return GetMethods().SubSpan(numVmethods_); 197 } 198 GetVirtualMethods()199 Span<Method> GetVirtualMethods() const 200 { 201 return {methods_, numVmethods_}; 202 } 203 GetCopiedMethods()204 Span<Method> GetCopiedMethods() const 205 { 206 Span<Method> res {methods_, numMethods_ + numCopiedMethods_}; 207 return res.SubSpan(numMethods_); 208 } 209 GetFields()210 Span<Field> GetFields() const 211 { 212 return {fields_, numFields_}; 213 } 214 GetStaticFields()215 Span<Field> GetStaticFields() const 216 { 217 return {fields_, numSfields_}; 218 } 219 GetInstanceFields()220 Span<Field> GetInstanceFields() const 221 { 222 return GetFields().SubSpan(numSfields_); 223 } 224 SetFields(Span<Field> fields,uint32_t numSfields)225 void SetFields(Span<Field> fields, uint32_t numSfields) 226 { 227 fields_ = fields.data(); 228 numFields_ = fields.size(); 229 numSfields_ = numSfields; 230 } 231 232 Span<Method *> GetVTable(); 233 234 Span<Method *const> GetVTable() const; 235 GetInterfaces()236 Span<Class *> GetInterfaces() const 237 { 238 return {ifaces_, numIfaces_}; 239 } 240 SetInterfaces(Span<Class * > ifaces)241 void SetInterfaces(Span<Class *> ifaces) 242 { 243 ifaces_ = ifaces.data(); 244 numIfaces_ = ifaces.size(); 245 } 246 GetIMT()247 Span<Method *> GetIMT() 248 { 249 return GetClassSpan().SubSpan<Method *>(GetIMTOffset(), imtSize_); 250 } 251 GetIMT()252 Span<Method *const> GetIMT() const 253 { 254 return GetClassSpan().SubSpan<Method *const>(GetIMTOffset(), imtSize_); 255 } 256 GetIMTableIndex(uint32_t methodOffset)257 uint32_t GetIMTableIndex(uint32_t methodOffset) const 258 { 259 ASSERT(imtSize_ != 0); 260 return methodOffset % imtSize_; 261 } 262 GetAccessFlags()263 uint32_t GetAccessFlags() const 264 { 265 return accessFlags_; 266 } 267 SetAccessFlags(uint32_t accessFlags)268 void SetAccessFlags(uint32_t accessFlags) 269 { 270 accessFlags_ = accessFlags; 271 } 272 IsPublic()273 bool IsPublic() const 274 { 275 return (accessFlags_ & ACC_PUBLIC) != 0; 276 } 277 IsProtected()278 bool IsProtected() const 279 { 280 return (accessFlags_ & ACC_PROTECTED) != 0; 281 } 282 IsPrivate()283 bool IsPrivate() const 284 { 285 return (accessFlags_ & ACC_PRIVATE) != 0; 286 } 287 IsFinal()288 bool IsFinal() const 289 { 290 return (accessFlags_ & ACC_FINAL) != 0; 291 } 292 IsAnnotation()293 bool IsAnnotation() const 294 { 295 return (accessFlags_ & ACC_ANNOTATION) != 0; 296 } 297 IsEnum()298 bool IsEnum() const 299 { 300 return (accessFlags_ & ACC_ENUM) != 0; 301 } 302 GetVTableSize()303 uint32_t GetVTableSize() const 304 { 305 return vtableSize_; 306 } 307 GetIMTSize()308 uint32_t GetIMTSize() const 309 { 310 return imtSize_; 311 } 312 GetClassSize()313 uint32_t GetClassSize() const 314 { 315 return classSize_; 316 } 317 GetObjectSize()318 uint32_t GetObjectSize() const 319 { 320 ASSERT(!IsVariableSize()); 321 return BaseClass::GetObjectSize(); 322 } 323 SetObjectSize(uint32_t size)324 void SetObjectSize(uint32_t size) 325 { 326 ASSERT(!IsVariableSize()); 327 BaseClass::SetObjectSize(size); 328 } 329 330 static uint32_t GetTypeSize(panda_file::Type type); 331 uint32_t GetComponentSize() const; 332 GetComponentType()333 Class *GetComponentType() const 334 { 335 return componentType_; 336 } 337 SetComponentType(Class * type)338 void SetComponentType(Class *type) 339 { 340 componentType_ = type; 341 } 342 IsArrayClass()343 bool IsArrayClass() const 344 { 345 return componentType_ != nullptr; 346 } 347 IsObjectArrayClass()348 bool IsObjectArrayClass() const 349 { 350 return IsArrayClass() && !componentType_->IsPrimitive(); 351 } 352 IsStringClass()353 bool IsStringClass() const 354 { 355 return (GetFlags() & STRING_CLASS) != 0; 356 } 357 SetStringClass()358 void SetStringClass() 359 { 360 SetFlags(GetFlags() | STRING_CLASS); 361 } 362 SetCloneable()363 void SetCloneable() 364 { 365 SetFlags(GetFlags() | IS_CLONEABLE); 366 } 367 IsVariableSize()368 bool IsVariableSize() const 369 { 370 return IsArrayClass() || IsStringClass(); 371 } 372 373 size_t GetStaticFieldsOffset() const; 374 GetType()375 panda_file::Type GetType() const 376 { 377 return type_; 378 } 379 SetType(panda_file::Type type)380 void SetType(panda_file::Type type) 381 { 382 type_ = type; 383 } 384 IsPrimitive()385 bool IsPrimitive() const 386 { 387 return type_.IsPrimitive(); 388 } 389 IsAbstract()390 bool IsAbstract() const 391 { 392 return (accessFlags_ & ACC_ABSTRACT) != 0; 393 } 394 IsInterface()395 bool IsInterface() const 396 { 397 return (accessFlags_ & ACC_INTERFACE) != 0; 398 } 399 IsClass()400 bool IsClass() const 401 { 402 return !IsPrimitive() && !IsInterface(); 403 } 404 IsInstantiable()405 bool IsInstantiable() const 406 { 407 return (IsClass() && !IsAbstract()) || IsArrayClass(); 408 } 409 IsObjectClass()410 bool IsObjectClass() const 411 { 412 return !IsPrimitive() && GetBase() == nullptr; 413 } 414 415 /** 416 * Check if the object is Class instance 417 * @return true if the object is Class instance 418 */ 419 bool IsClassClass() const; 420 421 bool IsSubClassOf(const Class *klass) const; 422 423 /** 424 * Check whether an instance of this class can be assigned from an instance of class "klass". 425 * Object of type O is instance of type T if O is the same as T or is subtype of T. For arrays T should be a root 426 * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements. 427 */ 428 bool IsAssignableFrom(const Class *klass) const; 429 IsProxy()430 bool IsProxy() const 431 { 432 return (GetAccessFlags() & ACC_PROXY) != 0; 433 } 434 435 bool Implements(const Class *klass) const; 436 SetITable(ITable itable)437 void SetITable(ITable itable) 438 { 439 itable_ = itable; 440 } 441 GetITable()442 ITable GetITable() const 443 { 444 return itable_; 445 } 446 GetState()447 State GetState() const 448 { 449 return state_; 450 } 451 452 PANDA_PUBLIC_API void SetState(State state); 453 IsVerified()454 bool IsVerified() const 455 { 456 return state_ >= State::VERIFIED; 457 } 458 IsInitializing()459 bool IsInitializing() const 460 { 461 return state_ == State::INITIALIZING; 462 } 463 IsInitialized()464 bool IsInitialized() const 465 { 466 return state_ == State::INITIALIZED; 467 } 468 IsLoaded()469 bool IsLoaded() const 470 { 471 return state_ >= State::LOADED; 472 } 473 IsErroneous()474 bool IsErroneous() const 475 { 476 return state_ == State::ERRONEOUS; 477 } 478 GetBaseOffset()479 static constexpr uint32_t GetBaseOffset() 480 { 481 return MEMBER_OFFSET(Class, base_); 482 } GetComponentTypeOffset()483 static constexpr uint32_t GetComponentTypeOffset() 484 { 485 return MEMBER_OFFSET(Class, componentType_); 486 } GetTypeOffset()487 static constexpr uint32_t GetTypeOffset() 488 { 489 return MEMBER_OFFSET(Class, type_); 490 } GetStateOffset()491 static constexpr uint32_t GetStateOffset() 492 { 493 return MEMBER_OFFSET(Class, state_); 494 } GetITableOffset()495 static constexpr uint32_t GetITableOffset() 496 { 497 return MEMBER_OFFSET(Class, itable_); 498 } 499 GetInitializedValue()500 uint8_t GetInitializedValue() 501 { 502 return static_cast<uint8_t>(State::INITIALIZED); 503 } 504 IsVerifiedSuccess()505 bool IsVerifiedSuccess() const 506 { 507 return (IsVerified() && (!IsErroneous())); 508 } SetInitTid(uint32_t id)509 void SetInitTid(uint32_t id) 510 { 511 initTid_ = id; 512 } 513 GetInitTid()514 uint32_t GetInitTid() const 515 { 516 return initTid_; 517 } 518 519 static constexpr size_t GetVTableOffset(); 520 GetNumVirtualMethods()521 uint32_t GetNumVirtualMethods() const 522 { 523 return numVmethods_; 524 } 525 SetNumVirtualMethods(uint32_t n)526 void SetNumVirtualMethods(uint32_t n) 527 { 528 numVmethods_ = n; 529 } 530 GetNumCopiedMethods()531 uint32_t GetNumCopiedMethods() const 532 { 533 return numCopiedMethods_; 534 } 535 SetNumCopiedMethods(uint32_t n)536 void SetNumCopiedMethods(uint32_t n) 537 { 538 numCopiedMethods_ = n; 539 } 540 GetNumStaticFields()541 uint32_t GetNumStaticFields() const 542 { 543 return numSfields_; 544 } 545 SetNumStaticFields(uint32_t n)546 void SetNumStaticFields(uint32_t n) 547 { 548 numSfields_ = n; 549 } 550 SetHasDefaultMethods()551 void SetHasDefaultMethods() 552 { 553 accessFlags_ |= ACC_HAS_DEFAULT_METHODS; 554 } 555 HasDefaultMethods()556 bool HasDefaultMethods() const 557 { 558 return (accessFlags_ & ACC_HAS_DEFAULT_METHODS) != 0; 559 } 560 561 size_t GetIMTOffset() const; 562 563 PANDA_PUBLIC_API std::string GetName() const; 564 GetLoadContext()565 ClassLinkerContext *GetLoadContext() const 566 { 567 ASSERT(loadContext_ != nullptr); 568 return loadContext_; 569 } 570 SetLoadContext(ClassLinkerContext * context)571 void SetLoadContext(ClassLinkerContext *context) 572 { 573 ASSERT(context != nullptr); 574 loadContext_ = context; 575 } 576 577 template <class Pred> 578 Field *FindInstanceField(Pred pred) const; 579 580 Field *FindInstanceFieldById(panda_file::File::EntityId id) const; 581 582 template <class Pred> 583 Field *FindStaticField(Pred pred) const; 584 585 Field *FindStaticFieldById(panda_file::File::EntityId id) const; 586 587 template <class Pred> 588 Field *FindField(Pred pred) const; 589 590 template <class Pred> 591 Field *FindDeclaredField(Pred pred) const; 592 593 Field *GetInstanceFieldByName(const uint8_t *mutf8Name) const; 594 595 Field *GetStaticFieldByName(const uint8_t *mutf8Name) const; 596 597 Field *GetDeclaredFieldByName(const uint8_t *mutf8Name) const; 598 599 Method *GetVirtualInterfaceMethod(panda_file::File::EntityId id) const; 600 601 Method *GetStaticInterfaceMethod(panda_file::File::EntityId id) const; 602 603 Method *GetStaticClassMethod(panda_file::File::EntityId id) const; 604 605 Method *GetVirtualClassMethod(panda_file::File::EntityId id) const; 606 607 Method *GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 608 609 Method *GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 610 611 Method *GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 612 613 Method *GetStaticClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 614 615 Method *GetVirtualClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 616 617 Method *GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 618 619 Method *GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 620 621 Method *GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 622 623 Method *GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 624 625 Method *GetDirectMethod(const uint8_t *mutf8Name) const; 626 627 Method *GetClassMethod(const uint8_t *mutf8Name) const; 628 629 Method *GetInterfaceMethod(const uint8_t *mutf8Name) const; 630 631 Method *ResolveVirtualMethod(const Method *method) const; 632 633 template <class T, bool IS_VOLATILE = false> 634 T GetFieldPrimitive(size_t offset) const; 635 636 template <class T, bool IS_VOLATILE = false> 637 void SetFieldPrimitive(size_t offset, T value); 638 639 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true> 640 ObjectHeader *GetFieldObject(size_t offset) const; 641 642 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true> 643 void SetFieldObject(size_t offset, ObjectHeader *value); 644 645 template <class T> 646 T GetFieldPrimitive(const Field &field) const; 647 648 template <class T> 649 void SetFieldPrimitive(const Field &field, T value); 650 651 template <bool NEED_READ_BARRIER = true> 652 ObjectHeader *GetFieldObject(const Field &field) const; 653 654 template <bool NEED_WRITE_BARRIER = true> 655 void SetFieldObject(const Field &field, ObjectHeader *value); 656 657 // Pass thread parameter to speed up interpreter 658 template <bool NEED_READ_BARRIER = true> 659 ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const; 660 661 template <bool NEED_WRITE_BARRIER = true> 662 void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value); 663 664 template <class T> 665 T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const; 666 667 template <class T> 668 void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 669 670 template <bool NEED_READ_BARRIER = true> 671 ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const; 672 673 template <bool NEED_WRITE_BARRIER = true> 674 void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 675 676 template <typename T> 677 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 678 679 template <bool NEED_WRITE_BARRIER = true> 680 bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 681 std::memory_order memoryOrder, bool strong); 682 683 template <typename T> 684 T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, 685 bool strong); 686 687 template <bool NEED_WRITE_BARRIER = true> 688 ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 689 std::memory_order memoryOrder, bool strong); 690 691 template <typename T> 692 T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 693 694 template <bool NEED_WRITE_BARRIER = true> 695 ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 696 697 template <typename T> 698 T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 699 700 template <typename T> 701 T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 702 703 template <typename T> 704 T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 705 706 template <typename T> 707 T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 708 709 void DumpClass(std::ostream &os, size_t flags); 710 711 static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId fileId); 712 713 // for synthetic classes, like arrays 714 static UniqId CalcUniqId(const uint8_t *descriptor); 715 GetUniqId()716 UniqId GetUniqId() const 717 { 718 // Atomic with acquire order reason: data race with uniq_id_ with dependecies on reads after the load which 719 // should become visible 720 auto id = uniqId_.load(std::memory_order_acquire); 721 if (id == 0) { 722 id = CalcUniqId(); 723 // Atomic with release order reason: data race with uniq_id_ with dependecies on writes before the store 724 // which should become visible acquire 725 uniqId_.store(id, std::memory_order_release); 726 } 727 return id; 728 } 729 SetRefFieldsNum(uint32_t num,bool isStatic)730 void SetRefFieldsNum(uint32_t num, bool isStatic) 731 { 732 if (isStatic) { 733 numRefsfields_ = num; 734 } else { 735 numReffields_ = num; 736 } 737 } 738 SetRefFieldsOffset(uint32_t offset,bool isStatic)739 void SetRefFieldsOffset(uint32_t offset, bool isStatic) 740 { 741 if (isStatic) { 742 offsetRefsfields_ = offset; 743 } else { 744 offsetReffields_ = offset; 745 } 746 } 747 SetVolatileRefFieldsNum(uint32_t num,bool isStatic)748 void SetVolatileRefFieldsNum(uint32_t num, bool isStatic) 749 { 750 if (isStatic) { 751 volatileRefsfieldsNum_ = num; 752 } else { 753 volatileReffieldsNum_ = num; 754 } 755 } 756 757 template <bool IS_STATIC> GetRefFieldsNum()758 uint32_t GetRefFieldsNum() const 759 { 760 return IS_STATIC ? numRefsfields_ : numReffields_; 761 } 762 763 template <bool IS_STATIC> GetRefFieldsOffset()764 uint32_t GetRefFieldsOffset() const 765 { 766 return IS_STATIC ? offsetRefsfields_ : offsetReffields_; 767 } 768 769 template <bool IS_STATIC> GetVolatileRefFieldsNum()770 uint32_t GetVolatileRefFieldsNum() const 771 { 772 return IS_STATIC ? volatileRefsfieldsNum_ : volatileReffieldsNum_; 773 } 774 ResolveClassIndex(panda_file::File::Index idx)775 panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const 776 { 777 return classIdx_[idx]; 778 } 779 ResolveMethodIndex(panda_file::File::Index idx)780 panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const 781 { 782 return methodIdx_[idx]; 783 } 784 ResolveFieldIndex(panda_file::File::Index idx)785 panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const 786 { 787 return fieldIdx_[idx]; 788 } 789 GetClassIndex()790 Span<const panda_file::File::EntityId> GetClassIndex() const 791 { 792 return classIdx_; 793 } 794 SetClassIndex(Span<const panda_file::File::EntityId> index)795 void SetClassIndex(Span<const panda_file::File::EntityId> index) 796 { 797 classIdx_ = index; 798 } 799 GetMethodIndex()800 Span<const panda_file::File::EntityId> GetMethodIndex() const 801 { 802 return methodIdx_; 803 } 804 SetMethodIndex(Span<const panda_file::File::EntityId> index)805 void SetMethodIndex(Span<const panda_file::File::EntityId> index) 806 { 807 methodIdx_ = index; 808 } 809 GetFieldIndex()810 Span<const panda_file::File::EntityId> GetFieldIndex() const 811 { 812 return fieldIdx_; 813 } 814 SetFieldIndex(Span<const panda_file::File::EntityId> index)815 void SetFieldIndex(Span<const panda_file::File::EntityId> index) 816 { 817 fieldIdx_ = index; 818 } 819 820 static Class *FromClassObject(const ObjectHeader *obj); 821 822 static size_t GetClassObjectSizeFromClass(Class *cls, panda_file::SourceLang lang); 823 GetMethodsOffset()824 static inline constexpr size_t GetMethodsOffset() 825 { 826 return MEMBER_OFFSET(Class, methods_); 827 } 828 829 ~Class() = default; 830 831 NO_COPY_SEMANTIC(Class); 832 NO_MOVE_SEMANTIC(Class); 833 834 static constexpr size_t ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields, 835 size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields, 836 size_t numRefSfields, size_t numTaggedSfields); 837 LookupFieldByName(panda_file::File::StringData name)838 Field *LookupFieldByName(panda_file::File::StringData name) const 839 { 840 for (auto &f : GetFields()) { 841 if (name == f.GetName()) { 842 return &f; 843 } 844 } 845 return nullptr; 846 } 847 848 template <panda_file::Type::TypeId FIELD_TYPE> LookupGetterByName(panda_file::File::StringData name)849 Method *LookupGetterByName(panda_file::File::StringData name) const 850 { 851 for (auto &m : GetMethods()) { 852 if (name != m.GetName()) { 853 continue; 854 } 855 auto retType = m.GetReturnType(); 856 if (retType.IsVoid()) { 857 continue; 858 } 859 if (m.GetNumArgs() != 1) { 860 continue; 861 } 862 if (!m.GetArgType(0).IsReference()) { 863 continue; 864 } 865 if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) { 866 if (retType.IsPrimitive()) { 867 continue; 868 } 869 return &m; 870 } 871 872 if (retType.IsReference()) { 873 continue; 874 } 875 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) { 876 if (retType.GetBitWidth() != coretypes::INT64_BITS) { 877 continue; 878 } 879 } else { 880 if (retType.GetBitWidth() > coretypes::INT32_BITS) { 881 continue; 882 } 883 } 884 return &m; 885 } 886 return nullptr; 887 } 888 889 template <panda_file::Type::TypeId FIELD_TYPE> LookupSetterByName(panda_file::File::StringData name)890 Method *LookupSetterByName(panda_file::File::StringData name) const 891 { 892 for (auto &m : GetMethods()) { 893 if (name != m.GetName()) { 894 continue; 895 } 896 if (!m.GetReturnType().IsVoid()) { 897 continue; 898 } 899 if (m.GetNumArgs() != 2U) { 900 continue; 901 } 902 if (!m.GetArgType(0).IsReference()) { 903 continue; 904 } 905 if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) { 906 if (m.GetArgType(1).IsPrimitive()) { 907 continue; 908 } 909 return &m; 910 } 911 912 auto arg1 = m.GetArgType(1); 913 if (arg1.IsReference()) { 914 continue; 915 } 916 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) { 917 if (arg1.GetBitWidth() != coretypes::INT64_BITS) { 918 continue; 919 } 920 } else { 921 if (arg1.GetBitWidth() > coretypes::INT32_BITS) { 922 continue; 923 } 924 } 925 return &m; 926 } 927 return nullptr; 928 } 929 930 private: 931 static constexpr void Pad(size_t size, size_t *padding, size_t *n); 932 933 enum class FindFilter { STATIC, INSTANCE, ALL, COPIED }; 934 935 template <FindFilter FILTER> 936 Span<Field> GetFields() const; 937 938 template <FindFilter FILTER, class Pred> 939 Field *FindDeclaredField(Pred pred) const; 940 941 template <FindFilter FILTER> 942 Field *FindDeclaredField(panda_file::File::EntityId id) const; 943 944 template <FindFilter FILTER, class Pred> 945 Field *FindFieldInInterfaces(const Class *kls, Pred pred) const; 946 947 template <FindFilter FILTER, class Pred> 948 Field *FindField(Pred pred) const; 949 950 template <FindFilter FILTER> 951 Span<Method> GetMethods() const; 952 953 template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 954 Method *FindDirectMethod(Key key, const Pred &...preds) const; 955 956 template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 957 Method *FindClassMethod(Key key, const Pred &...preds) const; 958 959 template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 960 Method *FindInterfaceMethod(Key key, const Pred &...preds) const; 961 GetClassSpan()962 Span<std::byte> GetClassSpan() 963 { 964 return Span(reinterpret_cast<std::byte *>(this), classSize_); 965 } 966 GetClassSpan()967 Span<const std::byte> GetClassSpan() const 968 { 969 return Span(reinterpret_cast<const std::byte *>(this), classSize_); 970 } 971 972 private: 973 Class *base_ {nullptr}; 974 const panda_file::File *pandaFile_ {nullptr}; 975 // Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information. 976 const uint8_t *descriptor_; 977 Method *methods_ {nullptr}; 978 Field *fields_ {nullptr}; 979 Class **ifaces_ {nullptr}; 980 981 panda_file::File::EntityId fileId_ {}; 982 uint32_t vtableSize_; 983 uint32_t imtSize_; 984 uint32_t classSize_; 985 uint32_t accessFlags_ {0}; 986 987 uint32_t numMethods_ {0}; 988 uint32_t numVmethods_ {0}; 989 uint32_t numCopiedMethods_ {0}; 990 uint32_t numFields_ {0}; 991 uint32_t numSfields_ {0}; 992 uint32_t numIfaces_ {0}; 993 uint32_t initTid_ {0}; 994 995 ITable itable_; 996 997 // For array types this field contains array's element size, for non-array type it should be zero. 998 Class *componentType_ {nullptr}; 999 1000 ClassLinkerContext *loadContext_ {nullptr}; 1001 1002 panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE}; 1003 std::atomic<State> state_; 1004 1005 UniqId CalcUniqId() const; 1006 mutable std::atomic<UniqId> uniqId_ {0}; 1007 1008 uint32_t numReffields_ {0}; // instance reference fields num 1009 uint32_t numRefsfields_ {0}; // static reference fields num 1010 uint32_t offsetReffields_ {0}; // first instance reference fields offset in object layout 1011 uint32_t offsetRefsfields_ {0}; // first static reference fields offset in object layout 1012 uint32_t volatileReffieldsNum_ {0}; 1013 uint32_t volatileRefsfieldsNum_ {0}; 1014 1015 Span<const panda_file::File::EntityId> classIdx_ {nullptr, nullptr}; 1016 Span<const panda_file::File::EntityId> methodIdx_ {nullptr, nullptr}; 1017 Span<const panda_file::File::EntityId> fieldIdx_ {nullptr, nullptr}; 1018 }; 1019 1020 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, const Class::State &state); 1021 1022 } // namespace ark 1023 1024 #endif // PANDA_RUNTIME_CLASS_H_ 1025