isa_t指針結(jié)構(gòu)

前言

在前面的探索對象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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末评腺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子淑掌,更是在濱河造成了極大的恐慌蒿讥,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抛腕,死亡現(xiàn)場離奇詭異芋绸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)担敌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門摔敛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柄错,你說我怎么就攤上這事舷夺。” “怎么了售貌?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵给猾,是天一觀的道長。 經(jīng)常有香客問我颂跨,道長敢伸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任恒削,我火速辦了婚禮池颈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钓丰。我一直安慰自己躯砰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布携丁。 她就那樣靜靜地躺著琢歇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上李茫,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天揭保,我揣著相機(jī)與錄音,去河邊找鬼魄宏。 笑死秸侣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宠互。 我是一名探鬼主播味榛,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼名秀!你這毒婦竟也來了励负?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匕得,失蹤者是張志新(化名)和其女友劉穎继榆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汁掠,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡略吨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了考阱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翠忠。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖乞榨,靈堂內(nèi)的尸體忽然破棺而出秽之,到底是詐尸還是另有隱情,我是刑警寧澤吃既,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布考榨,位于F島的核電站,受9級特大地震影響鹦倚,放射性物質(zhì)發(fā)生泄漏河质。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一震叙、第九天 我趴在偏房一處隱蔽的房頂上張望掀鹅。 院中可真熱鬧,春花似錦媒楼、人聲如沸乐尊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽科吭。三九已至昏滴,卻和暖如春猴鲫,著一層夾襖步出監(jiān)牢的瞬間对人,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工拂共, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留牺弄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓宜狐,卻偏偏與公主長得像势告,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抚恒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容