前言
在前面的探索對象alloc流程中绢片,對于對象開辟的空間需要關(guān)聯(lián)類的isa指針.相關(guān)源碼代碼如下
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的結(jié)構(gòu)是isa_t類型
探索isa_t結(jié)構(gòu)
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 是一個聯(lián)合體結(jié)構(gòu)!
1.1 什么是聯(lián)合體呢?
“聯(lián)合”是一種特殊的類,也是一種構(gòu)造類型的數(shù)據(jù)結(jié)構(gòu)。在一個“聯(lián)合”內(nèi)可以定義多種不同的數(shù)據(jù)類型, 一個被說明為該“聯(lián)合”類型的變量中迈套,允許裝入該“聯(lián)合”所定義的任何一種數(shù)據(jù),這些數(shù)據(jù)共享同一段內(nèi)存碱鳞,以達(dá)到節(jié)省空間的目的(還有一個節(jié)省空間的類型:位域)桑李。 這是一個非常特殊的地方,也是聯(lián)合的特征窿给。另外贵白,同struct一樣,聯(lián)合默認(rèn)訪問權(quán)限也是公有的崩泡,并且禁荒,也具有成員函數(shù)。
1.2 union isa_t內(nèi)部具體分析
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架構(gòu)下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 指針開啟指針優(yōu)化 0:純isa指針呛伴,1:不止是類對象地址,isa 中包含了類信息、對象的引用計數(shù)等
has_assoc
:關(guān)聯(lián)對象標(biāo)志位谒所,0沒有热康,1存在
has_cxx_dtor
:該對象是否有 C++ 或者 Objc 的析構(gòu)器,如果有析構(gòu)函數(shù),則需要做析構(gòu)邏輯, 如果沒有,則可以更快的釋放對象
shiftcls
:存儲類指針的值。開啟指針優(yōu)化的情況下劣领,在 arm64 架構(gòu)中有 33 位用來存儲類指針姐军。
magic
:用于調(diào)試器判斷當(dāng)前對象是真的對象還是沒有初始化的空間
weakly_referenced:
對象是否被指向或者曾經(jīng)指向一個 ARC 的弱變量,沒有弱引用的對象可以更快釋放剖踊。
has_sidetable_rc
:當(dāng)對象引用技術(shù)大于 10 時庶弃,則需要借用該變量存儲進(jìn)位
extra_rc
:當(dāng)表示該對象的引用計數(shù)值,實際上是引用計數(shù)值減 1德澈, 例如,如果對象的引用計數(shù)為 10固惯,那么 extra_rc 為 9梆造。如果引用計數(shù)大于 10, 則需要使用到上面的 has_sidetable_rc。
驗證一下在x86-64設(shè)備上創(chuàng)建一個ZFPerson對象镇辉,它的isa指針結(jié)構(gòu)如下
打印出cls的地址,cls = 0x011d800100001541
查看cls地址的二進(jìn)制數(shù)組屡穗,剛好與isa_t在x86上的結(jié)構(gòu)數(shù)據(jù)對應(yīng)上,第一位是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關(guān)聯(lián)類
在isa_t類中有下面兩個方法
void setClass(Class cls, objc_object *obj);
Class getClass(bool authenticated);
1.3.1 isa設(shè)置類信息
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關(guān)于 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構(gòu)建模擬器時也是如此村砂。
ARM64e是arm64e架構(gòu),用于Apple A12及更高版本A系列處理器或新型OS_SIMULATOR 模擬器的設(shè)備屹逛。
__has_feature(ptrauth_calls): 是判斷編譯器是否支持指針身份驗證功能
ptrauth_calls 指針身份驗證础废,針對arm64e架構(gòu);使用Apple A12或更高版本A系列處理器的設(shè)備(如iPhone XS罕模、iPhone XS Max和iPhone XR或更新的設(shè)備)支持arm64e架構(gòu)