1 /** 2 * Copyright (c) 2021-2022 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 panda { 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 IsInstantiable()400 bool IsInstantiable() const 401 { 402 return (!IsPrimitive() && !IsAbstract() && !IsInterface()) || IsArrayClass(); 403 } 404 IsObjectClass()405 bool IsObjectClass() const 406 { 407 return !IsPrimitive() && GetBase() == nullptr; 408 } 409 410 /** 411 * Check if the object is Class instance 412 * @return true if the object is Class instance 413 */ 414 bool IsClassClass() const; 415 416 bool IsSubClassOf(const Class *klass) const; 417 418 /** 419 * Check whether an instance of this class can be assigned from an instance of class "klass". 420 * 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 421 * type in type hierarchy or T is such array that O array elements are the same or subtype of T array elements. 422 */ 423 bool IsAssignableFrom(const Class *klass) const; 424 IsProxy()425 bool IsProxy() const 426 { 427 return (GetAccessFlags() & ACC_PROXY) != 0; 428 } 429 430 bool Implements(const Class *klass) const; 431 SetITable(ITable itable)432 void SetITable(ITable itable) 433 { 434 itable_ = itable; 435 } 436 GetITable()437 ITable GetITable() const 438 { 439 return itable_; 440 } 441 GetState()442 State GetState() const 443 { 444 return state_; 445 } 446 447 PANDA_PUBLIC_API void SetState(State state); 448 IsVerified()449 bool IsVerified() const 450 { 451 return state_ >= State::VERIFIED; 452 } 453 IsInitializing()454 bool IsInitializing() const 455 { 456 return state_ == State::INITIALIZING; 457 } 458 IsInitialized()459 bool IsInitialized() const 460 { 461 return state_ == State::INITIALIZED; 462 } 463 IsLoaded()464 bool IsLoaded() const 465 { 466 return state_ >= State::LOADED; 467 } 468 IsErroneous()469 bool IsErroneous() const 470 { 471 return state_ == State::ERRONEOUS; 472 } 473 GetBaseOffset()474 static constexpr uint32_t GetBaseOffset() 475 { 476 return MEMBER_OFFSET(Class, base_); 477 } GetComponentTypeOffset()478 static constexpr uint32_t GetComponentTypeOffset() 479 { 480 return MEMBER_OFFSET(Class, componentType_); 481 } GetTypeOffset()482 static constexpr uint32_t GetTypeOffset() 483 { 484 return MEMBER_OFFSET(Class, type_); 485 } GetStateOffset()486 static constexpr uint32_t GetStateOffset() 487 { 488 return MEMBER_OFFSET(Class, state_); 489 } GetITableOffset()490 static constexpr uint32_t GetITableOffset() 491 { 492 return MEMBER_OFFSET(Class, itable_); 493 } 494 GetInitializedValue()495 uint8_t GetInitializedValue() 496 { 497 return static_cast<uint8_t>(State::INITIALIZED); 498 } 499 IsVerifiedSuccess()500 bool IsVerifiedSuccess() const 501 { 502 return (IsVerified() && (!IsErroneous())); 503 } SetInitTid(uint32_t id)504 void SetInitTid(uint32_t id) 505 { 506 initTid_ = id; 507 } 508 GetInitTid()509 uint32_t GetInitTid() const 510 { 511 return initTid_; 512 } 513 514 static constexpr size_t GetVTableOffset(); 515 GetNumVirtualMethods()516 uint32_t GetNumVirtualMethods() const 517 { 518 return numVmethods_; 519 } 520 SetNumVirtualMethods(uint32_t n)521 void SetNumVirtualMethods(uint32_t n) 522 { 523 numVmethods_ = n; 524 } 525 GetNumCopiedMethods()526 uint32_t GetNumCopiedMethods() const 527 { 528 return numCopiedMethods_; 529 } 530 SetNumCopiedMethods(uint32_t n)531 void SetNumCopiedMethods(uint32_t n) 532 { 533 numCopiedMethods_ = n; 534 } 535 GetNumStaticFields()536 uint32_t GetNumStaticFields() const 537 { 538 return numSfields_; 539 } 540 SetNumStaticFields(uint32_t n)541 void SetNumStaticFields(uint32_t n) 542 { 543 numSfields_ = n; 544 } 545 SetHasDefaultMethods()546 void SetHasDefaultMethods() 547 { 548 accessFlags_ |= ACC_HAS_DEFAULT_METHODS; 549 } 550 HasDefaultMethods()551 bool HasDefaultMethods() const 552 { 553 return (accessFlags_ & ACC_HAS_DEFAULT_METHODS) != 0; 554 } 555 556 size_t GetIMTOffset() const; 557 558 PANDA_PUBLIC_API std::string GetName() const; 559 GetLoadContext()560 ClassLinkerContext *GetLoadContext() const 561 { 562 ASSERT(loadContext_ != nullptr); 563 return loadContext_; 564 } 565 SetLoadContext(ClassLinkerContext * context)566 void SetLoadContext(ClassLinkerContext *context) 567 { 568 ASSERT(context != nullptr); 569 loadContext_ = context; 570 } 571 572 template <class Pred> 573 Field *FindInstanceField(Pred pred) const; 574 575 Field *FindInstanceFieldById(panda_file::File::EntityId id) const; 576 577 template <class Pred> 578 Field *FindStaticField(Pred pred) const; 579 580 Field *FindStaticFieldById(panda_file::File::EntityId id) const; 581 582 template <class Pred> 583 Field *FindField(Pred pred) const; 584 585 template <class Pred> 586 Field *FindDeclaredField(Pred pred) const; 587 588 Field *GetInstanceFieldByName(const uint8_t *mutf8Name) const; 589 590 Field *GetStaticFieldByName(const uint8_t *mutf8Name) const; 591 592 Field *GetDeclaredFieldByName(const uint8_t *mutf8Name) const; 593 594 Method *GetVirtualInterfaceMethod(panda_file::File::EntityId id) const; 595 596 Method *GetStaticInterfaceMethod(panda_file::File::EntityId id) const; 597 598 Method *GetStaticClassMethod(panda_file::File::EntityId id) const; 599 600 Method *GetVirtualClassMethod(panda_file::File::EntityId id) const; 601 602 Method *GetDirectMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 603 604 Method *GetClassMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 605 606 Method *GetClassMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 607 608 Method *GetStaticClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 609 610 Method *GetVirtualClassMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 611 612 Method *GetInterfaceMethod(const uint8_t *mutf8Name, const Method::Proto &proto) const; 613 614 Method *GetInterfaceMethod(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 615 616 Method *GetStaticInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 617 618 Method *GetVirtualInterfaceMethodByName(const panda_file::File::StringData &sd, const Method::Proto &proto) const; 619 620 Method *GetDirectMethod(const uint8_t *mutf8Name) const; 621 622 Method *GetClassMethod(const uint8_t *mutf8Name) const; 623 624 Method *GetInterfaceMethod(const uint8_t *mutf8Name) const; 625 626 Method *ResolveVirtualMethod(const Method *method) const; 627 628 template <class T, bool IS_VOLATILE = false> 629 T GetFieldPrimitive(size_t offset) const; 630 631 template <class T, bool IS_VOLATILE = false> 632 void SetFieldPrimitive(size_t offset, T value); 633 634 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true> 635 ObjectHeader *GetFieldObject(size_t offset) const; 636 637 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true> 638 void SetFieldObject(size_t offset, ObjectHeader *value); 639 640 template <class T> 641 T GetFieldPrimitive(const Field &field) const; 642 643 template <class T> 644 void SetFieldPrimitive(const Field &field, T value); 645 646 template <bool NEED_READ_BARRIER = true> 647 ObjectHeader *GetFieldObject(const Field &field) const; 648 649 template <bool NEED_WRITE_BARRIER = true> 650 void SetFieldObject(const Field &field, ObjectHeader *value); 651 652 // Pass thread parameter to speed up interpreter 653 template <bool NEED_READ_BARRIER = true> 654 ObjectHeader *GetFieldObject(ManagedThread *thread, const Field &field) const; 655 656 template <bool NEED_WRITE_BARRIER = true> 657 void SetFieldObject(ManagedThread *thread, const Field &field, ObjectHeader *value); 658 659 template <class T> 660 T GetFieldPrimitive(size_t offset, std::memory_order memoryOrder) const; 661 662 template <class T> 663 void SetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 664 665 template <bool NEED_READ_BARRIER = true> 666 ObjectHeader *GetFieldObject(size_t offset, std::memory_order memoryOrder) const; 667 668 template <bool NEED_WRITE_BARRIER = true> 669 void SetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 670 671 template <typename T> 672 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 673 674 template <bool NEED_WRITE_BARRIER = true> 675 bool CompareAndSetFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 676 std::memory_order memoryOrder, bool strong); 677 678 template <typename T> 679 T CompareAndExchangeFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, 680 bool strong); 681 682 template <bool NEED_WRITE_BARRIER = true> 683 ObjectHeader *CompareAndExchangeFieldObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 684 std::memory_order memoryOrder, bool strong); 685 686 template <typename T> 687 T GetAndSetFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 688 689 template <bool NEED_WRITE_BARRIER = true> 690 ObjectHeader *GetAndSetFieldObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 691 692 template <typename T> 693 T GetAndAddFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 694 695 template <typename T> 696 T GetAndBitwiseOrFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 697 698 template <typename T> 699 T GetAndBitwiseAndFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 700 701 template <typename T> 702 T GetAndBitwiseXorFieldPrimitive(size_t offset, T value, std::memory_order memoryOrder); 703 704 void DumpClass(std::ostream &os, size_t flags); 705 706 static UniqId CalcUniqId(const panda_file::File *file, panda_file::File::EntityId fileId); 707 708 // for synthetic classes, like arrays 709 static UniqId CalcUniqId(const uint8_t *descriptor); 710 GetUniqId()711 UniqId GetUniqId() const 712 { 713 // Atomic with acquire order reason: data race with uniq_id_ with dependecies on reads after the load which 714 // should become visible 715 auto id = uniqId_.load(std::memory_order_acquire); 716 if (id == 0) { 717 id = CalcUniqId(); 718 // Atomic with release order reason: data race with uniq_id_ with dependecies on writes before the store 719 // which should become visible acquire 720 uniqId_.store(id, std::memory_order_release); 721 } 722 return id; 723 } 724 SetRefFieldsNum(uint32_t num,bool isStatic)725 void SetRefFieldsNum(uint32_t num, bool isStatic) 726 { 727 if (isStatic) { 728 numRefsfields_ = num; 729 } else { 730 numReffields_ = num; 731 } 732 } 733 SetRefFieldsOffset(uint32_t offset,bool isStatic)734 void SetRefFieldsOffset(uint32_t offset, bool isStatic) 735 { 736 if (isStatic) { 737 offsetRefsfields_ = offset; 738 } else { 739 offsetReffields_ = offset; 740 } 741 } 742 SetVolatileRefFieldsNum(uint32_t num,bool isStatic)743 void SetVolatileRefFieldsNum(uint32_t num, bool isStatic) 744 { 745 if (isStatic) { 746 volatileRefsfieldsNum_ = num; 747 } else { 748 volatileReffieldsNum_ = num; 749 } 750 } 751 752 template <bool IS_STATIC> GetRefFieldsNum()753 uint32_t GetRefFieldsNum() const 754 { 755 return IS_STATIC ? numRefsfields_ : numReffields_; 756 } 757 758 template <bool IS_STATIC> GetRefFieldsOffset()759 uint32_t GetRefFieldsOffset() const 760 { 761 return IS_STATIC ? offsetRefsfields_ : offsetReffields_; 762 } 763 764 template <bool IS_STATIC> GetVolatileRefFieldsNum()765 uint32_t GetVolatileRefFieldsNum() const 766 { 767 return IS_STATIC ? volatileRefsfieldsNum_ : volatileReffieldsNum_; 768 } 769 ResolveClassIndex(panda_file::File::Index idx)770 panda_file::File::EntityId ResolveClassIndex(panda_file::File::Index idx) const 771 { 772 return classIdx_[idx]; 773 } 774 ResolveMethodIndex(panda_file::File::Index idx)775 panda_file::File::EntityId ResolveMethodIndex(panda_file::File::Index idx) const 776 { 777 return methodIdx_[idx]; 778 } 779 ResolveFieldIndex(panda_file::File::Index idx)780 panda_file::File::EntityId ResolveFieldIndex(panda_file::File::Index idx) const 781 { 782 return fieldIdx_[idx]; 783 } 784 GetClassIndex()785 Span<const panda_file::File::EntityId> GetClassIndex() const 786 { 787 return classIdx_; 788 } 789 SetClassIndex(Span<const panda_file::File::EntityId> index)790 void SetClassIndex(Span<const panda_file::File::EntityId> index) 791 { 792 classIdx_ = index; 793 } 794 GetMethodIndex()795 Span<const panda_file::File::EntityId> GetMethodIndex() const 796 { 797 return methodIdx_; 798 } 799 SetMethodIndex(Span<const panda_file::File::EntityId> index)800 void SetMethodIndex(Span<const panda_file::File::EntityId> index) 801 { 802 methodIdx_ = index; 803 } 804 GetFieldIndex()805 Span<const panda_file::File::EntityId> GetFieldIndex() const 806 { 807 return fieldIdx_; 808 } 809 SetFieldIndex(Span<const panda_file::File::EntityId> index)810 void SetFieldIndex(Span<const panda_file::File::EntityId> index) 811 { 812 fieldIdx_ = index; 813 } 814 815 static Class *FromClassObject(const ObjectHeader *obj); 816 817 static size_t GetClassObjectSizeFromClass(Class *cls, panda_file::SourceLang lang); 818 GetMethodsOffset()819 static inline constexpr size_t GetMethodsOffset() 820 { 821 return MEMBER_OFFSET(Class, methods_); 822 } 823 824 ~Class() = default; 825 826 NO_COPY_SEMANTIC(Class); 827 NO_MOVE_SEMANTIC(Class); 828 829 static constexpr size_t ComputeClassSize(size_t vtableSize, size_t imtSize, size_t num8bitSfields, 830 size_t num16bitSfields, size_t num32bitSfields, size_t num64bitSfields, 831 size_t numRefSfields, size_t numTaggedSfields); 832 LookupFieldByName(panda_file::File::StringData name)833 Field *LookupFieldByName(panda_file::File::StringData name) const 834 { 835 for (auto &f : GetFields()) { 836 if (name == f.GetName()) { 837 return &f; 838 } 839 } 840 return nullptr; 841 } 842 843 template <panda_file::Type::TypeId FIELD_TYPE> LookupGetterByName(panda_file::File::StringData name)844 Method *LookupGetterByName(panda_file::File::StringData name) const 845 { 846 for (auto &m : GetMethods()) { 847 if (name != m.GetName()) { 848 continue; 849 } 850 auto retType = m.GetReturnType(); 851 if (retType.IsVoid()) { 852 continue; 853 } 854 if (m.GetNumArgs() != 1) { 855 continue; 856 } 857 if (!m.GetArgType(0).IsReference()) { 858 continue; 859 } 860 if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) { 861 if (retType.IsPrimitive()) { 862 continue; 863 } 864 } else { 865 if (retType.IsReference()) { 866 continue; 867 } 868 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) { 869 if (retType.GetBitWidth() != coretypes::INT64_BITS) { 870 continue; 871 } 872 } else { 873 if (retType.GetBitWidth() > coretypes::INT32_BITS) { 874 continue; 875 } 876 } 877 } 878 return &m; 879 } 880 return nullptr; 881 } 882 883 template <panda_file::Type::TypeId FIELD_TYPE> LookupSetterByName(panda_file::File::StringData name)884 Method *LookupSetterByName(panda_file::File::StringData name) const 885 { 886 for (auto &m : GetMethods()) { 887 if (name != m.GetName()) { 888 continue; 889 } 890 if (!m.GetReturnType().IsVoid()) { 891 continue; 892 } 893 if (m.GetNumArgs() != 2U) { 894 continue; 895 } 896 if (!m.GetArgType(0).IsReference()) { 897 continue; 898 } 899 if constexpr (FIELD_TYPE == panda_file::Type::TypeId::REFERENCE) { 900 if (m.GetArgType(1).IsPrimitive()) { 901 continue; 902 } 903 } else { 904 auto arg1 = m.GetArgType(1); 905 if (arg1.IsReference()) { 906 continue; 907 } 908 if constexpr (panda_file::Type(FIELD_TYPE).GetBitWidth() == coretypes::INT64_BITS) { 909 if (arg1.GetBitWidth() != coretypes::INT64_BITS) { 910 continue; 911 } 912 } else { 913 if (arg1.GetBitWidth() > coretypes::INT32_BITS) { 914 continue; 915 } 916 } 917 } 918 return &m; 919 } 920 return nullptr; 921 } 922 923 private: 924 static constexpr void Pad(size_t size, size_t *padding, size_t *n); 925 926 enum class FindFilter { STATIC, INSTANCE, ALL, COPIED }; 927 928 template <FindFilter FILTER> 929 Span<Field> GetFields() const; 930 931 template <FindFilter FILTER, class Pred> 932 Field *FindDeclaredField(Pred pred) const; 933 934 template <FindFilter FILTER> 935 Field *FindDeclaredField(panda_file::File::EntityId id) const; 936 937 template <FindFilter FILTER, class Pred> 938 Field *FindField(Pred pred) const; 939 940 template <FindFilter FILTER> 941 Span<Method> GetMethods() const; 942 943 template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 944 Method *FindDirectMethod(Key key, const Pred &...preds) const; 945 946 template <FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 947 Method *FindClassMethod(Key key, const Pred &...preds) const; 948 949 template <Class::FindFilter FILTER, typename KeyComp, typename Key, typename... Pred> 950 Method *FindInterfaceMethod(Key key, const Pred &...preds) const; 951 GetClassSpan()952 Span<std::byte> GetClassSpan() 953 { 954 return Span(reinterpret_cast<std::byte *>(this), classSize_); 955 } 956 GetClassSpan()957 Span<const std::byte> GetClassSpan() const 958 { 959 return Span(reinterpret_cast<const std::byte *>(this), classSize_); 960 } 961 962 private: 963 Class *base_ {nullptr}; 964 const panda_file::File *pandaFile_ {nullptr}; 965 // Decscriptor is a valid MUTF8 string. See docs/file_format.md#typedescriptor for more information. 966 const uint8_t *descriptor_; 967 Method *methods_ {nullptr}; 968 Field *fields_ {nullptr}; 969 Class **ifaces_ {nullptr}; 970 971 panda_file::File::EntityId fileId_ {}; 972 uint32_t vtableSize_; 973 uint32_t imtSize_; 974 uint32_t classSize_; 975 uint32_t accessFlags_ {0}; 976 977 uint32_t numMethods_ {0}; 978 uint32_t numVmethods_ {0}; 979 uint32_t numCopiedMethods_ {0}; 980 uint32_t numFields_ {0}; 981 uint32_t numSfields_ {0}; 982 uint32_t numIfaces_ {0}; 983 uint32_t initTid_ {0}; 984 985 ITable itable_; 986 987 // For array types this field contains array's element size, for non-array type it should be zero. 988 Class *componentType_ {nullptr}; 989 990 ClassLinkerContext *loadContext_ {nullptr}; 991 992 panda_file::Type type_ {panda_file::Type::TypeId::REFERENCE}; 993 std::atomic<State> state_; 994 995 UniqId CalcUniqId() const; 996 mutable std::atomic<UniqId> uniqId_ {0}; 997 998 uint32_t numReffields_ {0}; // instance reference fields num 999 uint32_t numRefsfields_ {0}; // static reference fields num 1000 uint32_t offsetReffields_ {0}; // first instance reference fields offset in object layout 1001 uint32_t offsetRefsfields_ {0}; // first static reference fields offset in object layout 1002 uint32_t volatileReffieldsNum_ {0}; 1003 uint32_t volatileRefsfieldsNum_ {0}; 1004 1005 Span<const panda_file::File::EntityId> classIdx_ {nullptr, nullptr}; 1006 Span<const panda_file::File::EntityId> methodIdx_ {nullptr, nullptr}; 1007 Span<const panda_file::File::EntityId> fieldIdx_ {nullptr, nullptr}; 1008 }; 1009 1010 PANDA_PUBLIC_API std::ostream &operator<<(std::ostream &os, const Class::State &state); 1011 1012 } // namespace panda 1013 1014 #endif // PANDA_RUNTIME_CLASS_H 1015