美文网首页
iOS底层系列02--objc_object与objc_clas

iOS底层系列02--objc_object与objc_clas

作者: YanZi_33 | 来源:发表于2021-02-03 16:26 被阅读0次
    • 在objc4的源码中有这么几个常见的结构体:

    struct objc_object

    struct objc_object {
    private:
        isa_t isa;
    
    public:
        // ISA() assumes this is NOT a tagged pointer object
        Class ISA(bool authenticated = false);
    
        // rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
        Class rawISA();
    
        // getIsa() allows this to be a tagged pointer object
        Class getIsa();
        
        uintptr_t isaBits() const;
    
        // initIsa() should be used to init the isa of new objects only.
        // If this object already has an isa, use changeIsa() for correctness.
        // initInstanceIsa(): objects with no custom RR/AWZ
        // initClassIsa(): class objects
        // initProtocolIsa(): protocol objects
        // initIsa(): other objects
        void initIsa(Class cls /*nonpointer=false*/);
        void initClassIsa(Class cls /*nonpointer=maybe*/);
        void initProtocolIsa(Class cls /*nonpointer=maybe*/);
        void initInstanceIsa(Class cls, bool hasCxxDtor);
    
        // changeIsa() should be used to change the isa of existing objects.
        // If this is a new object, use initIsa() for performance.
        Class changeIsa(Class newCls);
        //指针优化与带标记的指针小对象 
        bool hasNonpointerIsa();
        bool isTaggedPointer();
        bool isTaggedPointerOrNil();
        bool isBasicTaggedPointer();
        bool isExtTaggedPointer();
        bool isClass();
    
        // object may have associated objects?
        //关联对象 
        bool hasAssociatedObjects();
        void setHasAssociatedObjects();
    
        // object may be weakly referenced?
        //对象的弱引用指针
        bool isWeaklyReferenced();
        void setWeaklyReferenced_nolock();
    
        // object may have -.cxx_destruct implementation?
        bool hasCxxDtor();
    
        // Optimized calls to retain/release methods
        //以下是内存管理相关的函数
        id retain();
        void release();
        id autorelease();
    
        // Implementations of retain/release methods
        id rootRetain();
        bool rootRelease();
        id rootAutorelease();
        bool rootTryRetain();
        bool rootReleaseShouldDealloc();
        uintptr_t rootRetainCount();
    
        // Implementation of dealloc methods
        bool rootIsDeallocating();
        void clearDeallocating();
        void rootDealloc();
    
    private:
        void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
    
        // Slow paths for inline control
        id rootAutorelease2();
        uintptr_t overrelease_error();
    
    #if SUPPORT_NONPOINTER_ISA
        // Controls what parts of root{Retain,Release} to emit/inline
        // - Full means the full (slow) implementation
        // - Fast means the fastpaths only
        // - FastOrMsgSend means the fastpaths but checking whether we should call
        //   -retain/-release or Swift, for the usage of objc_{retain,release}
        enum class RRVariant {
            Full,
            Fast,
            FastOrMsgSend,
        };
    
        // Unified retain count manipulation for nonpointer isa
        inline id rootRetain(bool tryRetain, RRVariant variant);
        inline bool rootRelease(bool performDealloc, RRVariant variant);
        id rootRetain_overflow(bool tryRetain);
        uintptr_t rootRelease_underflow(bool performDealloc);
    
        void clearDeallocating_slow();
    
        // Side table retain count overflow for nonpointer isa
        struct SidetableBorrow { size_t borrowed, remaining; };
    
        void sidetable_lock();
        void sidetable_unlock();
    
        void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
        bool sidetable_addExtraRC_nolock(size_t delta_rc);
        SidetableBorrow sidetable_subExtraRC_nolock(size_t delta_rc);
        size_t sidetable_getExtraRC_nolock();
        void sidetable_clearExtraRC_nolock();
    #endif
    
        // Side-table-only retain count
        // 内存关联的底层数据结构 -- 散列表
        bool sidetable_isDeallocating();
        void sidetable_clearDeallocating();
    
        bool sidetable_isWeaklyReferenced();
        void sidetable_setWeaklyReferenced_nolock();
    
        id sidetable_retain(bool locked = false);
        id sidetable_retain_slow(SideTable& table);
    
        uintptr_t sidetable_release(bool locked = false, bool performDealloc = true);
        uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
    
        bool sidetable_tryRetain();
    
        uintptr_t sidetable_retainCount();
    #if DEBUG
        bool sidetable_present();
    #endif
    };
    
    • isa成员:OC对象的isa指针;
    • Class ISA(bool authenticated = false):获取obj的isa指针所指向的class,必须保证obj不是taggedPonter对象;
    inline Class objc_object::ISA(bool authenticated){
        //断言 若传入TaggedPointer对象 会崩溃
        ASSERT(!isTaggedPointer());
        return isa.getDecodedClass(authenticated);
    }
    
    • Class rawISA():获取obj的isa指针所指向的class,必须保证obj不是taggedPonter对象或者obj是nonpointer,即isa指针经过优化的;
    inline Class objc_object::rawISA(){
        //断言 必须为非taggedPonter对象或isa指针经过优化
        ASSERT(!isTaggedPointer() && !isa.nonpointer);
        return (Class)isa.bits;
    }
    
    • Class getIsa():获取obj的isa指针;
    inline Class objc_object::getIsa() {
        if (fastpath(!isTaggedPointer())) return ISA();
    
        extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
        uintptr_t slot, ptr = (uintptr_t)this;
        Class cls;
    
        slot = (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
        cls = objc_tag_classes[slot];
        if (slowpath(cls == (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer)) {
            slot = (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
            cls = objc_tag_ext_classes[slot];
        }
        return cls;
    }
    
    • 大概率执行if (fastpath(!isTaggedPointer())) return ISA()

    • 允许传入TaggedPointer对象;

    • 初始化isa指针有以下几个函数:

    • void initIsa(Class cls /*nonpointer=false*/)

    • void initClassIsa(Class cls /*nonpointer=maybe*/)

    • void initProtocolIsa(Class cls /*nonpointer=maybe*/)

    • void initInstanceIsa(Class cls, bool hasCxxDtor)

    • 最终都会执行下面的函数实现:

    inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor){ 
        //必须保证obj是非标记指针的OC对象
        ASSERT(!isTaggedPointer()); 
        
        isa_t newisa(0);
    
        if (!nonpointer) {
            newisa.setClass(cls, this);
        } else {
            ASSERT(!DisableNonpointerIsa);
            ASSERT(!cls->instancesRequireRawIsa());
    
    #if SUPPORT_INDEXED_ISA
            ASSERT(cls->classArrayIndex() > 0);
            newisa.bits = ISA_INDEX_MAGIC_VALUE;
            // isa.magic is part of ISA_MAGIC_VALUE
            // isa.nonpointer is part of ISA_MAGIC_VALUE
            newisa.has_cxx_dtor = hasCxxDtor;
            newisa.indexcls = (uintptr_t)cls->classArrayIndex();
    #else
            newisa.bits = ISA_MAGIC_VALUE;
            // isa.magic is part of ISA_MAGIC_VALUE
            // isa.nonpointer is part of ISA_MAGIC_VALUE
    #   if ISA_HAS_CXX_DTOR_BIT
            newisa.has_cxx_dtor = hasCxxDtor;
    #   endif
            newisa.setClass(cls, this);
    #endif
            newisa.extra_rc = 1;
        }
    
        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
    
    • Class changeIsa(Class newCls): 更改对象的isa指针指向,本质是改变对象所属的类class,与KVO的底层实现类似;
    • 其他部分详细内容见源码注释;

    struct objc_class

    struct objc_class : objc_object {
      objc_class(const objc_class&) = delete;
      objc_class(objc_class&&) = delete;
      void operator=(const objc_class&) = delete;
      void operator=(objc_class&&) = delete;
        
        //Class ISA;
        //父类指针
        Class superclass;
        //缓存 -- 主要做方法缓存
        cache_t cache;             // formerly cache pointer and vtable
        //存储类信息的结构体
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    
        Class getSuperclass() const {}
    
        void setSuperclass(Class newSuperclass) {}
        //获取类的数据
        class_rw_t *data() const {
            return bits.data();
        }
        void setData(class_rw_t *newData) {
            bits.setData(newData);
        }
    
        void setInfo(uint32_t set) {
            ASSERT(isFuture()  ||  isRealized());
            data()->setFlags(set);
        }
    
        void clearInfo(uint32_t clear) {
            ASSERT(isFuture()  ||  isRealized());
            data()->clearFlags(clear);
        }
    
        // set and clear must not overlap
        void changeInfo(uint32_t set, uint32_t clear) {
            ASSERT(isFuture()  ||  isRealized());
            ASSERT((set & clear) == 0);
            data()->changeFlags(set, clear);
        }
       //是否有自定义的内存管理方法
    #if FAST_HAS_DEFAULT_RR
        bool hasCustomRR() const {
            return !bits.getBit(FAST_HAS_DEFAULT_RR);
        }
        void setHasDefaultRR() {
            bits.setBits(FAST_HAS_DEFAULT_RR);
        }
        void setHasCustomRR() {
            bits.clearBits(FAST_HAS_DEFAULT_RR);
        }
    #else
        bool hasCustomRR() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
        }
        void setHasDefaultRR() {
            bits.data()->setFlags(RW_HAS_DEFAULT_RR);
        }
        void setHasCustomRR() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
        }
    #endif
    
    //是否有自定义的allocWithZone方法
    #if FAST_CACHE_HAS_DEFAULT_AWZ
        bool hasCustomAWZ() const {
            return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
        void setHasDefaultAWZ() {
            cache.setBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
        void setHasCustomAWZ() {
            cache.clearBit(FAST_CACHE_HAS_DEFAULT_AWZ);
        }
    #else
        bool hasCustomAWZ() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_AWZ);
        }
        void setHasDefaultAWZ() {
            bits.data()->setFlags(RW_HAS_DEFAULT_AWZ);
        }
        void setHasCustomAWZ() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_AWZ);
        }
    #endif
    
    //是否有对象构造,初始化的核心方法
    #if FAST_CACHE_HAS_DEFAULT_CORE
        bool hasCustomCore() const {
            return !cache.getBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
        void setHasDefaultCore() {
            return cache.setBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
        void setHasCustomCore() {
            return cache.clearBit(FAST_CACHE_HAS_DEFAULT_CORE);
        }
    #else
        bool hasCustomCore() const {
            return !(bits.data()->flags & RW_HAS_DEFAULT_CORE);
        }
        void setHasDefaultCore() {
            bits.data()->setFlags(RW_HAS_DEFAULT_CORE);
        }
        void setHasCustomCore() {
            bits.data()->clearFlags(RW_HAS_DEFAULT_CORE);
        }
    #endif
    
    //对象的C++方法
    #if FAST_CACHE_HAS_CXX_DTOR
        bool hasCxxDtor() {
            ASSERT(isRealized());
            return cache.getBit(FAST_CACHE_HAS_CXX_DTOR);
        }
        void setHasCxxDtor() {
            cache.setBit(FAST_CACHE_HAS_CXX_DTOR);
        }
    #else
        bool hasCxxDtor() {
            ASSERT(isRealized());
            return bits.data()->flags & RW_HAS_CXX_DTOR;
        }
        void setHasCxxDtor() {
            bits.data()->setFlags(RW_HAS_CXX_DTOR);
        }
    #endif
    
    //对象的isa指针
    //RAW_ISA --> 非TaggedPointer且isa优化过的OC对象
    #if FAST_CACHE_REQUIRES_RAW_ISA
        bool instancesRequireRawIsa() {
            return cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);
        }
        void setInstancesRequireRawIsa() {
            cache.setBit(FAST_CACHE_REQUIRES_RAW_ISA);
        }
    #elif SUPPORT_NONPOINTER_ISA
        bool instancesRequireRawIsa() {
            return bits.data()->flags & RW_REQUIRES_RAW_ISA;
        }
        void setInstancesRequireRawIsa() {
            bits.data()->setFlags(RW_REQUIRES_RAW_ISA);
        }
    #else
        bool instancesRequireRawIsa() {
            return true;
        }
        void setInstancesRequireRawIsa() {
            // nothing
        }
    #endif
        void setInstancesRequireRawIsaRecursively(bool inherited = false);
        void printInstancesRequireRawIsa(bool inherited);
    
    #if CONFIG_USE_PREOPT_CACHES
        bool allowsPreoptCaches() const {
            return !(bits.data()->flags & RW_NOPREOPT_CACHE);
        }
        bool allowsPreoptInlinedSels() const {
            return !(bits.data()->flags & RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptCaches() {
            bits.data()->setFlags(RW_NOPREOPT_CACHE | RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptInlinedSels() {
            bits.data()->setFlags(RW_NOPREOPT_SELS);
        }
        void setDisallowPreoptCachesRecursively(const char *why);
        void setDisallowPreoptInlinedSelsRecursively(const char *why);
    #else
        bool allowsPreoptCaches() const { return false; }
        bool allowsPreoptInlinedSels() const { return false; }
        void setDisallowPreoptCaches() { }
        void setDisallowPreoptInlinedSels() { }
        void setDisallowPreoptCachesRecursively(const char *why) { }
        void setDisallowPreoptInlinedSelsRecursively(const char *why) { }
    #endif
    
        bool canAllocNonpointer() {
            ASSERT(!isFuture());
            return !instancesRequireRawIsa();
        }
    
        bool isSwiftStable() {
            return bits.isSwiftStable();
        }
    
        bool isSwiftLegacy() {
            return bits.isSwiftLegacy();
        }
    
        bool isAnySwift() {
            return bits.isAnySwift();
        }
    
        bool isSwiftStable_ButAllowLegacyForNow() {
            return bits.isSwiftStable_ButAllowLegacyForNow();
        }
    
        uint32_t swiftClassFlags() {
            return *(uint32_t *)(&bits + 1);
        }
      
        bool usesSwiftRefcounting() {
            if (!isSwiftStable()) return false;
            return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
        }
    
        bool canCallSwiftRR() {
            // !hasCustomCore() is being used as a proxy for isInitialized(). All
            // classes with Swift refcounting are !hasCustomCore() (unless there are
            // category or swizzling shenanigans), but that bit is not set until a
            // class is initialized. Checking isInitialized requires an extra
            // indirection that we want to avoid on RR fast paths.
            //
            // In the unlikely event that someone causes a class with Swift
            // refcounting to be hasCustomCore(), we'll fall back to sending -retain
            // or -release, which is still correct.
            return !hasCustomCore() && usesSwiftRefcounting();
        }
    
        bool isStubClass() const {
            uintptr_t isa = (uintptr_t)isaBits();
            return 1 <= isa && isa < 16;
        }
    
        // Swift stable ABI built for old deployment targets looks weird.
        // The is-legacy bit is set for compatibility with old libobjc.
        // We are on a "new" deployment target so we need to rewrite that bit.
        // These stable-with-legacy-bit classes are distinguished from real
        // legacy classes using another bit in the Swift data
        // (ClassFlags::IsSwiftPreStableABI)
    
        bool isUnfixedBackwardDeployingStableSwift() {
            // Only classes marked as Swift legacy need apply.
            if (!bits.isSwiftLegacy()) return false;
    
            // Check the true legacy vs stable distinguisher.
            // The low bit of Swift's ClassFlags is SET for true legacy
            // and UNSET for stable pretending to be legacy.
            bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
            return !isActuallySwiftLegacy;
        }
    
        void fixupBackwardDeployingStableSwift() {
            if (isUnfixedBackwardDeployingStableSwift()) {
                // Class really is stable Swift, pretending to be pre-stable.
                // Fix its lie.
                bits.setIsSwiftStable();
            }
        }
    
        _objc_swiftMetadataInitializer swiftMetadataInitializer() {
            return bits.swiftMetadataInitializer();
        }
    
        // Return YES if the class's ivars are managed by ARC, 
        // or the class is MRC but has ARC-style weak ivars.
        //类成员变量的内存管理由ARC管理
       //但类是MRC管理
        bool hasAutomaticIvars() {
            return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
        }
    
        // Return YES if the class's ivars are managed by ARC.
        bool isARC() {
            return data()->ro()->flags & RO_IS_ARC;
        }
    
    
        bool forbidsAssociatedObjects() {
            return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
        }
    
    #if SUPPORT_NONPOINTER_ISA
        // Tracked in non-pointer isas; not tracked otherwise
    #else
        bool instancesHaveAssociatedObjects() {
            // this may be an unrealized future class in the CF-bridged case
            ASSERT(isFuture()  ||  isRealized());
            return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
        }
    
        void setInstancesHaveAssociatedObjects() {
            // this may be an unrealized future class in the CF-bridged case
            ASSERT(isFuture()  ||  isRealized());
            setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
        }
    #endif
    
        bool shouldGrowCache() {
            return true;
        }
    
        void setShouldGrowCache(bool) {
            // fixme good or bad for memory use?
        }
    
        bool isInitializing() {
            return getMeta()->data()->flags & RW_INITIALIZING;
        }
    
        void setInitializing() {
            ASSERT(!isMetaClass());
            ISA()->setInfo(RW_INITIALIZING);
        }
    
        bool isInitialized() {
            return getMeta()->data()->flags & RW_INITIALIZED;
        }
    
        void setInitialized();
    
        bool isLoadable() {
            ASSERT(isRealized());
            return true;  // any class registered for +load is definitely loadable
        }
    
        IMP getLoadMethod();
    
        // Locking: To prevent concurrent realization, hold runtimeLock.
        bool isRealized() const {
            return !isStubClass() && (data()->flags & RW_REALIZED);
        }
    
        // Returns true if this is an unrealized future class.
        // Locking: To prevent concurrent realization, hold runtimeLock.
        bool isFuture() const {
            if (isStubClass())
                return false;
            return data()->flags & RW_FUTURE;
        }
    
        bool isMetaClass() const {
            ASSERT_THIS_NOT_NULL;
            ASSERT(isRealized());
    #if FAST_CACHE_META
            return cache.getBit(FAST_CACHE_META);
    #else
            return data()->flags & RW_META;
    #endif
        }
    
        // Like isMetaClass, but also valid on un-realized classes
        bool isMetaClassMaybeUnrealized() {
            static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
            static_assert(RO_META == RW_META, "flags alias");
            if (isStubClass())
                return false;
            return data()->flags & RW_META;
        }
    
        // NOT identical to this->ISA when this is a metaclass
        Class getMeta() {
            if (isMetaClassMaybeUnrealized()) return (Class)this;
            else return this->ISA();
        }
    
        bool isRootClass() {
            return getSuperclass() == nil;
        }
        bool isRootMetaclass() {
            return ISA() == (Class)this;
        }
      
        // If this class does not have a name already, we can ask Swift to construct one for us.
        const char *installMangledNameForLazilyNamedClass();
    
        // Get the class's mangled name, or NULL if the class has a lazy
        // name that hasn't been created yet.
        const char *nonlazyMangledName() const {
            return bits.safe_ro()->getName();
        }
    
        const char *mangledName() { 
            // fixme can't assert locks here
            ASSERT_THIS_NOT_NULL;
    
            const char *result = nonlazyMangledName();
    
            if (!result) {
                // This class lazily instantiates its name. Emplace and
                // return it.
                result = installMangledNameForLazilyNamedClass();
            }
    
            return result;
        }
        
        const char *demangledName(bool needsLock);
        const char *nameForLogging();
    
        // May be unaligned depending on class's ivars.
        uint32_t unalignedInstanceStart() const {
            ASSERT(isRealized());
            return data()->ro()->instanceStart;
        }
    
        // Class's instance start rounded up to a pointer-size boundary.
        // This is used for ARC layout bitmaps.
        uint32_t alignedInstanceStart() const {
            return word_align(unalignedInstanceStart());
        }
    
        // May be unaligned depending on class's ivars.
        uint32_t unalignedInstanceSize() const {
            ASSERT(isRealized());
            return data()->ro()->instanceSize;
        }
    
        // Class's ivar size rounded up to a pointer-size boundary.
        uint32_t alignedInstanceSize() const {
            return word_align(unalignedInstanceSize());
        }
    
        inline size_t instanceSize(size_t extraBytes) const {
            if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
                return cache.fastInstanceSize(extraBytes);
            }
    
            size_t size = alignedInstanceSize() + extraBytes;
            // CF requires all objects be at least 16 bytes.
            if (size < 16) size = 16;
            return size;
        }
    
        void setInstanceSize(uint32_t newSize) {
            ASSERT(isRealized());
            ASSERT(data()->flags & RW_REALIZING);
            auto ro = data()->ro();
            if (newSize != ro->instanceSize) {
                ASSERT(data()->flags & RW_COPIED_RO);
                *const_cast<uint32_t *>(&ro->instanceSize) = newSize;
            }
            cache.setFastInstanceSize(newSize);
        }
    
        void chooseClassArrayIndex();
    
        void setClassArrayIndex(unsigned Idx) {
            bits.setClassArrayIndex(Idx);
        }
    
        unsigned classArrayIndex() {
            return bits.classArrayIndex();
        }
    };
    
    • superclass:指向父类的指针;
    • cache_t:方法调用缓存与实例对象内存大小的缓存,其结构体如下:

    cache_t

    struct cache_t {
    private:
        explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
        union {
            struct {
                explicit_atomic<mask_t>    _maybeMask;
    #if __LP64__
                uint16_t                   _flags;
    #endif
                uint16_t                   _occupied;
            };
            explicit_atomic<preopt_cache_t *> _originalPreoptCache;
        };
    
        void incrementOccupied();
        void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
    
        void reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld);
        void collect_free(bucket_t *oldBuckets, mask_t oldCapacity);
    
        static bucket_t *emptyBuckets();
        static bucket_t *allocateBuckets(mask_t newCapacity);
        static bucket_t *emptyBucketsForCapacity(mask_t capacity, bool allocate = true);
        static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
        void bad_cache(id receiver, SEL sel) __attribute__((noreturn, cold));
    
    public:
        // The following four fields are public for objcdt's use only.
        // objcdt reaches into fields while the process is suspended
        // hence doesn't care for locks and pesky little details like this
        // and can safely use these.
        unsigned capacity() const;
        struct bucket_t *buckets() const;
        Class cls() const;
    
    #if CONFIG_USE_PREOPT_CACHES
        const preopt_cache_t *preopt_cache() const;
    #endif
    
        mask_t occupied() const;
        void initializeToEmpty();
    
    #if CONFIG_USE_PREOPT_CACHES
        bool isConstantOptimizedCache(bool strict = false, uintptr_t empty_addr = (uintptr_t)&_objc_empty_cache) const;
        bool shouldFlush(SEL sel, IMP imp) const;
        bool isConstantOptimizedCacheWithInlinedSels() const;
        Class preoptFallbackClass() const;
        void maybeConvertToPreoptimized();
        void initializeToEmptyOrPreoptimizedInDisguise();
    #else
        inline bool isConstantOptimizedCache(bool strict = false, uintptr_t empty_addr = 0) const { return false; }
        inline bool shouldFlush(SEL sel, IMP imp) const {
            return cache_getImp(cls(), sel) == imp;
        }
        inline bool isConstantOptimizedCacheWithInlinedSels() const { return false; }
        inline void initializeToEmptyOrPreoptimizedInDisguise() { initializeToEmpty(); }
    #endif
    
        void insert(SEL sel, IMP imp, id receiver);
        void copyCacheNolock(objc_imp_cache_entry *buffer, int len);
        void destroy();
        void eraseNolock(const char *func);
    
        static void init();
        static void collectNolock(bool collectALot);
        static size_t bytesForCapacity(uint32_t cap);
    
    #if __LP64__
        bool getBit(uint16_t flags) const {
            return _flags & flags;
        }
        void setBit(uint16_t set) {
            __c11_atomic_fetch_or((_Atomic(uint16_t) *)&_flags, set, __ATOMIC_RELAXED);
        }
        void clearBit(uint16_t clear) {
            __c11_atomic_fetch_and((_Atomic(uint16_t) *)&_flags, ~clear, __ATOMIC_RELAXED);
        }
    #endif
    
    #if FAST_CACHE_ALLOC_MASK
        bool hasFastInstanceSize(size_t extra) const
        {
            if (__builtin_constant_p(extra) && extra == 0) {
                return _flags & FAST_CACHE_ALLOC_MASK16;
            }
            return _flags & FAST_CACHE_ALLOC_MASK;
        }
    
        size_t fastInstanceSize(size_t extra) const
        {
            ASSERT(hasFastInstanceSize(extra));
    
            if (__builtin_constant_p(extra) && extra == 0) {
                return _flags & FAST_CACHE_ALLOC_MASK16;
            } else {
                size_t size = _flags & FAST_CACHE_ALLOC_MASK;
                // remove the FAST_CACHE_ALLOC_DELTA16 that was added
                // by setFastInstanceSize
                return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
            }
        }
    
        void setFastInstanceSize(size_t newSize)
        {
            // Set during realization or construction only. No locking needed.
            uint16_t newBits = _flags & ~FAST_CACHE_ALLOC_MASK;
            uint16_t sizeBits;
    
            // Adding FAST_CACHE_ALLOC_DELTA16 allows for FAST_CACHE_ALLOC_MASK16
            // to yield the proper 16byte aligned allocation size with a single mask
            sizeBits = word_align(newSize) + FAST_CACHE_ALLOC_DELTA16;
            sizeBits &= FAST_CACHE_ALLOC_MASK;
            if (newSize <= sizeBits) {
                newBits |= sizeBits;
            }
            _flags = newBits;
        }
    #else
        bool hasFastInstanceSize(size_t extra) const {
            return false;
        }
        size_t fastInstanceSize(size_t extra) const {
            abort();
        }
        void setFastInstanceSize(size_t extra) {
            // nothing
        }
    #endif
    };
    
    • class_data_bits_t:是一个结构体,此结构体存储了类的数据,其结构如下所示:

    class_data_bits_t

    struct class_data_bits_t {
        friend objc_class;
    
        // Values are the FAST_ flags above.
        uintptr_t bits;
    private:
        bool getBit(uintptr_t bit) const
        {
            return bits & bit;
        }
    
        // Atomically set the bits in `set` and clear the bits in `clear`.
        // set and clear must not overlap.
        void setAndClearBits(uintptr_t set, uintptr_t clear)
        {
            ASSERT((set & clear) == 0);
            uintptr_t newBits, oldBits = LoadExclusive(&bits);
            do {
                newBits = (oldBits | set) & ~clear;
            } while (slowpath(!StoreReleaseExclusive(&bits, &oldBits, newBits)));
        }
    
        void setBits(uintptr_t set) {
            __c11_atomic_fetch_or((_Atomic(uintptr_t) *)&bits, set, __ATOMIC_RELAXED);
        }
    
        void clearBits(uintptr_t clear) {
            __c11_atomic_fetch_and((_Atomic(uintptr_t) *)&bits, ~clear, __ATOMIC_RELAXED);
        }
    
    public:
    
        class_rw_t* data() const {
            return (class_rw_t *)(bits & FAST_DATA_MASK);
        }
        void setData(class_rw_t *newData)
        {
            ASSERT(!data()  ||  (newData->flags & (RW_REALIZING | RW_FUTURE)));
            // Set during realization or construction only. No locking needed.
            // Use a store-release fence because there may be concurrent
            // readers of data and data's contents.
            uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
            atomic_thread_fence(memory_order_release);
            bits = newBits;
        }
    
        // Get the class's ro data, even in the presence of concurrent realization.
        // fixme this isn't really safe without a compiler barrier at least
        // and probably a memory barrier when realizeClass changes the data field
        const class_ro_t *safe_ro() const {
            class_rw_t *maybe_rw = data();
            if (maybe_rw->flags & RW_REALIZED) {
                // maybe_rw is rw
                return maybe_rw->ro();
            } else {
                // maybe_rw is actually ro
                return (class_ro_t *)maybe_rw;
            }
        }
    
    #if SUPPORT_INDEXED_ISA
        void setClassArrayIndex(unsigned Idx) {
            // 0 is unused as then we can rely on zero-initialisation from calloc.
            ASSERT(Idx > 0);
            data()->index = Idx;
        }
    #else
        void setClassArrayIndex(__unused unsigned Idx) {
        }
    #endif
    
        unsigned classArrayIndex() {
    #if SUPPORT_INDEXED_ISA
            return data()->index;
    #else
            return 0;
    #endif
        }
    
        bool isAnySwift() {
            return isSwiftStable() || isSwiftLegacy();
        }
    
        bool isSwiftStable() {
            return getBit(FAST_IS_SWIFT_STABLE);
        }
        void setIsSwiftStable() {
            setAndClearBits(FAST_IS_SWIFT_STABLE, FAST_IS_SWIFT_LEGACY);
        }
    
        bool isSwiftLegacy() {
            return getBit(FAST_IS_SWIFT_LEGACY);
        }
        void setIsSwiftLegacy() {
            setAndClearBits(FAST_IS_SWIFT_LEGACY, FAST_IS_SWIFT_STABLE);
        }
    
        // fixme remove this once the Swift runtime uses the stable bits
        bool isSwiftStable_ButAllowLegacyForNow() {
            return isAnySwift();
        }
    
        _objc_swiftMetadataInitializer swiftMetadataInitializer() {
            // This function is called on un-realized classes without
            // holding any locks.
            // Beware of races with other realizers.
            return safe_ro()->swiftMetadataInitializer();
        }
    };
    
    • bits与掩码FAST_DATA_MASK做位与运算可以得到class_rw_t结构体;
    • class_rw_t *data():获取类class的相关数据,返回是一个class_rw_t类型的结构体,表明类class的数据信息都存储在class_rw_t结构体中;
    class_rw_t结构体
    struct class_rw_t {
        // Be warned that Symbolication knows the layout of this structure.
        uint32_t flags;
        uint16_t witness;
    #if SUPPORT_INDEXED_ISA
        uint16_t index;
    #endif
        explicit_atomic<uintptr_t> ro_or_rw_ext;
    
        Class firstSubclass;
        Class nextSiblingClass;
    
    private:
        using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>;
    
        //联合 ro__rwe
        const ro_or_rw_ext_t get_ro_or_rwe() const {
            return ro_or_rw_ext_t{ro_or_rw_ext};
        }
    
        void set_ro_or_rwe(const class_ro_t *ro) {
            ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed);
        }
    
        void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {
            // the release barrier is so that the class_rw_ext_t::ro initialization
            // is visible to lockless readers
            rwe->ro = ro;
            ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release);
        }
    
        class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
    
    public:
        void setFlags(uint32_t set)
        {
            __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);
        }
    
        void clearFlags(uint32_t clear) 
        {
            __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);
        }
    
        // set and clear must not overlap
        void changeFlags(uint32_t set, uint32_t clear) 
        {
            ASSERT((set & clear) == 0);
    
            uint32_t oldf, newf;
            do {
                oldf = flags;
                newf = (oldf | set) & ~clear;
            } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
        }
    
        class_rw_ext_t *ext() const {
            return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
        }
    
        class_rw_ext_t *extAllocIfNeeded() {
            auto v = get_ro_or_rwe();
            if (fastpath(v.is<class_rw_ext_t *>())) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
            } else {
                return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
            }
        }
    
        class_rw_ext_t *deepCopy(const class_ro_t *ro) {
            return extAlloc(ro, true);
        }
    
        const class_ro_t *ro() const {
            auto v = get_ro_or_rwe();
            if (slowpath(v.is<class_rw_ext_t *>())) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
            }
            return v.get<const class_ro_t *>(&ro_or_rw_ext);
        }
    
        void set_ro(const class_ro_t *ro) {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
            } else {
                set_ro_or_rwe(ro);
            }
        }
    
        const method_array_t methods() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
            } else {
                return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
            }
        }
    
        const property_array_t properties() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
            } else {
                return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
            }
        }
    
        const protocol_array_t protocols() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
            } else {
                return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
            }
        }
    };
    
    • uint32_t flags:可以理解成描述类class的状态标识,其与不同的状态掩码值做位与运算可以得到类class的状态;
    • ro_or_rw_ext_t:是调用C++函数,将class_ro_tclass_rw_ext_t联合在一起,形成一个新的结构体;
    class_rw_ext_t
    struct class_rw_ext_t {
        DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
        class_ro_t_authed_ptr<const class_ro_t> ro;
        method_array_t methods;
        property_array_t properties;
        protocol_array_t protocols;
        char *demangledName;
        uint32_t version;
    };
    

    class_ro_t

    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;
    #ifdef __LP64__
        uint32_t reserved;
    #endif
    
        union {
            const uint8_t * ivarLayout;
            Class nonMetaclass;
        };
    
        explicit_atomic<const char *> name;
        // With ptrauth, this is signed if it points to a small list, but
        // may be unsigned if it points to a big list.
        void *baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars;
    
        const uint8_t * weakIvarLayout;
        property_list_t *baseProperties;
    
        // This field exists only when RO_HAS_SWIFT_INITIALIZER is set.
        _objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];
    
        _objc_swiftMetadataInitializer swiftMetadataInitializer() const {
            if (flags & RO_HAS_SWIFT_INITIALIZER) {
                return _swiftMetadataInitializer_NEVER_USE[0];
            } else {
                return nil;
            }
        }
    
        const char *getName() const {
            return name.load(std::memory_order_acquire);
        }
    
        static const uint16_t methodListPointerDiscriminator = 0xC310;
    #if 0 // FIXME: enable this when we get a non-empty definition of __ptrauth_objc_method_list_pointer from ptrauth.h.
            static_assert(std::is_same<
                          void * __ptrauth_objc_method_list_pointer *,
                          void * __ptrauth(ptrauth_key_method_list_pointer, 1, methodListPointerDiscriminator) *>::value,
                          "Method list pointer signing discriminator must match ptrauth.h");
    #endif
    
        method_list_t *baseMethods() const {
    #if __has_feature(ptrauth_calls)
            method_list_t *ptr = ptrauth_strip((method_list_t *)baseMethodList, ptrauth_key_method_list_pointer);
            if (ptr == nullptr)
                return nullptr;
    
            // Don't auth if the class_ro and the method list are both in the shared cache.
            // This is secure since they'll be read-only, and this allows the shared cache
            // to cut down on the number of signed pointers it has.
            bool roInSharedCache = objc::inSharedCache((uintptr_t)this);
            bool listInSharedCache = objc::inSharedCache((uintptr_t)ptr);
            if (roInSharedCache && listInSharedCache)
                return ptr;
    
            // Auth all other small lists.
            if (ptr->isSmallList())
                ptr = ptrauth_auth_data((method_list_t *)baseMethodList,
                                        ptrauth_key_method_list_pointer,
                                        ptrauth_blend_discriminator(&baseMethodList,
                                                                    methodListPointerDiscriminator));
            return ptr;
    #else
            return (method_list_t *)baseMethodList;
    #endif
        }
    
        uintptr_t baseMethodListPtrauthData() const {
            return ptrauth_blend_discriminator(&baseMethodList,
                                               methodListPointerDiscriminator);
        }
    
        class_ro_t *duplicate() const {
            bool hasSwiftInitializer = flags & RO_HAS_SWIFT_INITIALIZER;
    
            size_t size = sizeof(*this);
            if (hasSwiftInitializer)
                size += sizeof(_swiftMetadataInitializer_NEVER_USE[0]);
    
            class_ro_t *ro = (class_ro_t *)memdup(this, size);
    
            if (hasSwiftInitializer)
                ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];
    
    #if __has_feature(ptrauth_calls)
            // Re-sign the method list pointer if it was signed.
            // NOTE: It is possible for a signed pointer to have a signature
            // that is all zeroes. This is indistinguishable from a raw pointer.
            // This code will treat such a pointer as signed and re-sign it. A
            // false positive is safe: method list pointers are either authed or
            // stripped, so if baseMethods() doesn't expect it to be signed, it
            // will ignore the signature.
            void *strippedBaseMethodList = ptrauth_strip(baseMethodList, ptrauth_key_method_list_pointer);
            void *signedBaseMethodList = ptrauth_sign_unauthenticated(strippedBaseMethodList,
                                                                      ptrauth_key_method_list_pointer,
                                                                      baseMethodListPtrauthData());
            if (baseMethodList == signedBaseMethodList) {
                ro->baseMethodList = ptrauth_auth_and_resign(baseMethodList,
                                                             ptrauth_key_method_list_pointer,
                                                             baseMethodListPtrauthData(),
                                                             ptrauth_key_method_list_pointer,
                                                             ro->baseMethodListPtrauthData());
            } else {
                // Special case: a class_ro_t in the shared cache pointing to a
                // method list in the shared cache will not have a signed pointer,
                // but the duplicate will be expected to have a signed pointer since
                // it's not in the shared cache. Detect that and sign it.
                bool roInSharedCache = objc::inSharedCache((uintptr_t)this);
                bool listInSharedCache = objc::inSharedCache((uintptr_t)strippedBaseMethodList);
                if (roInSharedCache && listInSharedCache)
                    ro->baseMethodList = ptrauth_sign_unauthenticated(strippedBaseMethodList,
                                                                      ptrauth_key_method_list_pointer,
                                                                      ro->baseMethodListPtrauthData());
            }
    #endif
            return ro;
        }
    
        Class getNonMetaclass() const {
            ASSERT(flags & RO_META);
            return nonMetaclass;
        }
    
        const uint8_t *getIvarLayout() const {
            if (flags & RO_META)
                return nullptr;
            return ivarLayout;
        }
    };
    
    • flags:标识;
    • instanceSize:实例的内存大小;
    • baseMethodList:方法列表
    • baseProtocols:协议列表
    • baseProperties:属性列表
    • ivars:成员变量列表

    总结:

    • OC中的任意对象id,都是以objc_object为模板创建的,所以实例对象,类对象,元类对象都会有isa指针;

    • OC中的class类对象,都是以objc_class为模板创建,而objc_class继承自objc_object,所以也会有isa指针;

    • class_ro_t是其内部的成员;

    • Class的本质就是objc_class结构体

    typedef struct objc_class *Class;
    
    • id的本质就是objc_object结构体
    typedef struct objc_object *id;
    

    上述结构体之间的关系图如下:

    object_class.png
    • 从上述的结构图中可以看出,对象包括实例对象,类对象,元类对象,只要是继承自objc_object对象都有isa指针成员变量;
    • 类对象才有superClass指针,元类对象也存在superClass指针,只有是继承自objc_class的对象都有superClass指针,而实例对象是没有superClass指针的,表明实例对象之间是没有继承关系的,继承关系只表现在类对象与元类对象之间;

    断言Assert

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            BOOL isTaggedPointer = NO;
            assert(isTaggedPointer);
            NSLog(@"success");
        }
        return 0;
    }
    
    • assert(isTaggedPointer):会出现崩溃,因为参数isTaggedPointer = NO;
    • assert(参数),只有参数为真时,程序才会正常往下执行,否则会出现崩溃。

    相关文章

      网友评论

          本文标题:iOS底层系列02--objc_object与objc_clas

          本文链接:https://www.haomeiwen.com/subject/cieytltx.html