isa指针详解
在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址,从arm64架构开始,对isa进行了优化,变成了一个联合体(union)结构,还使用位域来存储更多的信息。
isa结构如下图:
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);
};
看结构体:
struct {
ISA_BITFIELD; // defined in isa.h
};
这个结构体用宏定义的方式表示,具体定义是根据结构模式和真机模拟器类型划分,详情见 isa.h文件。接下来以arm64为例:
# 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)
- nonpointer:是否是优化过的isa指针
苹果之前所有的结构都是32位的,在32位的时候isa指针只有指向对应类对象/元类对象的功能。而到了64位后,isa指针里面的信息更多,为了适配兼容,这一位用作区分。 - has_assoc:是否存在关联对象
记录对象是否动态添加(使用runtime API),关联对象。如果有则为1,否则为0。在对向释放的时候要检
查这个信息。 - has_cxx_dtor:是否存在c++析构函数
一般有属性的时候就会有析构函数,析构函数是用来释放成员变量的。 - shiftcls :class对象或者meta-class对象地址
存放class对象或者meta-class对象地址,在消息发送(objc_msgSend)的时候去找对应方法时候使用。 - magic:调试信息
用于在调试时分辨对象是否未完成初始化 - weakly_referenced:是否有被弱指针指向
如果有被弱指针指向,会在释放的时候去操作。如果没有则释放得更快 - unused:是否使用过
- has_sidetable_rc:引用计数是否存在sidetable中
如果为1,那么引用计数会存储在一个叫sidetable的类的属性中 - extra_rc:引用计数
如果引用计数大于19位(arm64 & 真机)的最大值(2的19次方-1),则把has_sidetable_rc置位1,把引用计数去存到sidetable中。