isa_t指针结构

前言

在前面的探索对象alloc流程中,对于对象开辟的空间需要关联类的isa指针.相关源码代码如下

inline void 
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{ 
    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;
}

从源码可以看出isa的结构是isa_t类型

探索isa_t结构

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    uintptr_t bits;

private:
    // Accessing the class requires custom ptrauth operations, so
    // force clients to go through setClass/getClass by making this
    // private.
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };

    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif

    void setClass(Class cls, objc_object *obj);
    Class getClass(bool authenticated);
    Class getDecodedClass(bool authenticated);
};

从源码可以看出,isa_t 是一个联合体结构!

1.1 什么是联合体呢?

“联合”是一种特殊的类,也是一种构造类型的数据结构。在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,以达到节省空间的目的(还有一个节省空间的类型:位域)。 这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且,也具有成员函数。

1.2 union isa_t内部具体分析

isa_t里面有一个

 struct {
       ISA_BITFIELD;  // defined in isa.h
 };
 

ISA_BITFIELD,是一个宏,

# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#     define ISA_MASK        0x007ffffffffffff8ULL
#     define ISA_MAGIC_MASK  0x0000000000000001ULL
#     define ISA_MAGIC_VALUE 0x0000000000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 0
#     define ISA_BITFIELD                                         
        uintptr_t nonpointer        : 1;                         
        uintptr_t has_assoc         : 1;                         
        uintptr_t weakly_referenced : 1;                         
        uintptr_t shiftcls_and_sig  : 52;                         
        uintptr_t has_sidetable_rc  : 1;                         
        uintptr_t extra_rc          : 8
#     define RC_ONE   (1ULL<<56)
#     define RC_HALF  (1ULL<<7)
#   else
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                         
        uintptr_t nonpointer        : 1;                         
        uintptr_t has_assoc         : 1;                         
        uintptr_t has_cxx_dtor      : 1;                         
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
        uintptr_t magic             : 6;                         
        uintptr_t weakly_referenced : 1;                         
        uintptr_t unused            : 1;                         
        uintptr_t has_sidetable_rc  : 1;                         
        uintptr_t extra_rc          : 19
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
#   endif

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                           
      uintptr_t nonpointer        : 1;                           
      uintptr_t has_assoc         : 1;                           
      uintptr_t has_cxx_dtor      : 1;                           
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ 
      uintptr_t magic             : 6;                           
      uintptr_t weakly_referenced : 1;                           
      uintptr_t unused            : 1;                           
      uintptr_t has_sidetable_rc  : 1;                           
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

# else
#   error unknown architecture for packed isa
# endif

我们先来看看arm64架构下ISA_BITFIELD的定义

 uintptr_t nonpointer        : 1;                         
 uintptr_t has_assoc         : 1;                         
 uintptr_t has_cxx_dtor      : 1;                         
 uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/
 uintptr_t magic             : 6;                         
 uintptr_t weakly_referenced : 1;                         
 uintptr_t unused            : 1;                         
 uintptr_t has_sidetable_rc  : 1;                         
 uintptr_t extra_rc          : 19

nonpointer:表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等

has_assoc:关联对象标志位,0没有,1存在

has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象

shiftcls:存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。

magic:用于调试器判断当前对象是真的对象还是没有初始化的空间

weakly_referenced:对象是否被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快释放。

has_sidetable_rc:当对象引用技术大于 10 时,则需要借用该变量存储进位
extra_rc:当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到上面的 has_sidetable_rc。

验证一下在x86-64设备上创建一个ZFPerson对象,它的isa指针结构如下

打印出cls的地址,cls = 0x011d800100001541


查看cls地址的二进制数组,刚好与isa_t在x86上的结构数据对应上,第一位是nonpointer,第47到52位是magic值111011H = 59D

__x86_64__
#   define ISA_BITFIELD                                           
      uintptr_t nonpointer        : 1;                           
      uintptr_t has_assoc         : 1;                           
      uintptr_t has_cxx_dtor      : 1;                           
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ 
      uintptr_t magic             : 6;                           
      uintptr_t weakly_referenced : 1;                           
      uintptr_t unused            : 1;                           
      uintptr_t has_sidetable_rc  : 1;                           
      uintptr_t extra_rc          : 8

1.3 isa关联类

在isa_t类中有下面两个方法

 void setClass(Class cls, objc_object *obj);
 Class getClass(bool authenticated);

1.3.1 isa设置类信息

inline void
isa_t::setClass(Class newCls, UNUSED_WITHOUT_PTRAUTH objc_object *obj)
{
    // Match the conditional in isa.h.
#if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#   if ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_NONE
    // No signing, just use the raw pointer.
    uintptr_t signedCls = (uintptr_t)newCls;

#   elif ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ONLY_SWIFT
    // We're only signing Swift classes. Non-Swift classes just use
    // the raw pointer
    uintptr_t signedCls = (uintptr_t)newCls;
    if (newCls->isSwiftStable())
        signedCls = (uintptr_t)ptrauth_sign_unauthenticated((void *)newCls, ISA_SIGNING_KEY, ptrauth_blend_discriminator(obj, ISA_SIGNING_DISCRIMINATOR));

#   elif ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL
    // We're signing everything
    uintptr_t signedCls = (uintptr_t)ptrauth_sign_unauthenticated((void *)newCls, ISA_SIGNING_KEY, ptrauth_blend_discriminator(obj, ISA_SIGNING_DISCRIMINATOR));

#   else
#       error Unknown isa signing mode.
#   endif

    shiftcls_and_sig = signedCls >> 3;

#elif SUPPORT_INDEXED_ISA
    // Indexed isa only uses this method to set a raw pointer class.
    // Setting an indexed class is handled separately.
    cls = newCls;

#else // Nonpointer isa, no ptrauth
    shiftcls = (uintptr_t)newCls >> 3;
#endif
}

1.3.2 isa获取class

1.4关于 if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR

// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.

//ARM64模拟器有更大的地址空间,所以使用ARM64e
//即使在为ARM64-not-e构建模拟器时也是如此。

ARM64e是arm64e架构,用于Apple A12及更高版本A系列处理器或新型OS_SIMULATOR 模拟器的设备。

__has_feature(ptrauth_calls): 是判断编译器是否支持指针身份验证功能
ptrauth_calls 指针身份验证,针对arm64e架构;使用Apple A12或更高版本A系列处理器的设备(如iPhone XS、iPhone XS Max和iPhone XR或更新的设备)支持arm64e架构

你可能感兴趣的:(isa_t指针结构)