swift的witness table

V-table和witness table

我們知道,執(zhí)行方法時,首先要查找到正確的方法,然后執(zhí)行.能夠在編譯期確定執(zhí)行方法的方式叫做靜態(tài)分派static dispatch,無法在編譯期確定,只能在運行時去確定執(zhí)行方法的分派方式叫做動態(tài)分派dynamic dispatch.
靜態(tài)分派更快,而且靜態(tài)分派可以進行內(nèi)聯(lián)等進一步的優(yōu)化操作,使得執(zhí)行更快速,性能更高.
但是對于多態(tài)的情況,我們不能在編譯期確定最終的類型,這里就用到了dynamic dispatch動態(tài)分派.動態(tài)分派的實現(xiàn)是,每種類型都會創(chuàng)建一張表,表內(nèi)是一個包含了方法指針的數(shù)組.
對于類class來說,每個類型都會創(chuàng)建虛函數(shù)表指針,指向一個叫做V-Table的表.擁有繼承關(guān)系的子類會在虛函數(shù)表內(nèi)通過繼承順序(C++可以實現(xiàn)多繼承)去展示虛函數(shù)表指針.
但是對于swift來說,class類和struct結(jié)構(gòu)體的實現(xiàn)是不同的,而屬于結(jié)構(gòu)體的協(xié)議Protocol,可以擁有屬性和實現(xiàn)方法,管理Protocol Type方法分派的表就叫做Protocol Witness Table.

witness table內(nèi)部結(jié)構(gòu)

witness table

和V-table一樣,Protocol Witness Table(簡稱PWT)內(nèi)存儲的是方法數(shù)組,里面包含了方法實現(xiàn)的指針地址,一般我們調(diào)用方法時,是通過獲取對象的內(nèi)存地址和方法的位移offset去查找的.
Protocol Witness Table是用于管理Protocol Type的方法調(diào)用的,在我們接觸swift性能優(yōu)化時,聽到另一個概念叫做Value Witness Table(簡稱VWT),這個又是做什么的呢?

什么是value witness table

value witness table

value witness table的結(jié)構(gòu)如上,是用于管理遵守了協(xié)議的Protocol Type實例的初始化,拷貝,內(nèi)存消減和銷毀的.
value witness table還可以拆分為%relative_vwtable%absolute_vwtable,我們這里先不做展開,之后會對這部分內(nèi)容進行補充.
value witness tableprotocol witness table通過分工,去管理Protocol Type實例的內(nèi)存管理(初始化,拷貝,銷毀)和方法調(diào)用.

說完witness table的結(jié)構(gòu),我們討論一下,在編譯器內(nèi)部實現(xiàn)中,SIL(swift intermediate language)內(nèi)部是如何實現(xiàn)vtable和witness table的.

V-Table在SIL的實現(xiàn)

decl ::= sil-vtable
sil-vtable ::= 'sil_vtable' identifier '{' sil-vtable-entry* '}'

sil-vtable-entry ::= sil-decl-ref ':' sil-linkage? sil-function-name

SIL使用 class_method, super_method, objc_method, 和 objc_super_method 操作來實現(xiàn)類方法的動態(tài)分派.
類的每一個方法,都被映射到SIL的方法實現(xiàn)

class A {
  func foo()
  func bar()
  func bas()
}

sil @A_foo : $@convention(thin) (@owned A) -> ()
sil @A_bar : $@convention(thin) (@owned A) -> ()
sil @A_bas : $@convention(thin) (@owned A) -> ()

sil_vtable A {
  #A.foo!1: @A_foo
  #A.bar!1: @A_bar
  #A.bas!1: @A_bas
}

class B : A {
  func bar()
}

sil @B_bar : $@convention(thin) (@owned B) -> ()

sil_vtable B {
  #A.foo!1: @A_foo
  #A.bar!1: @B_bar
  #A.bas!1: @A_bas
}

class C : B {
  func bas()
}

sil @C_bas : $@convention(thin) (@owned C) -> ()

sil_vtable C {
  #A.foo!1: @A_foo
  #A.bar!1: @B_bar
  #A.bas!1: @C_bas
}

需要注意的是,vtable中的方法聲明是指向最后的衍生類的方法的.swift的AST持有了聲明的重載關(guān)系,并用于在SIL的vtable中查找衍生類的重載方法.
為了防止SIL的方法是thunk,方法名使用了原始方法實現(xiàn)的連接(linkage)作為前綴.

Witness Tables在編譯期內(nèi)SIL階段的實現(xiàn)

decl ::= sil-witness-table
sil-witness-table ::= 'sil_witness_table' sil-linkage?
                      normal-protocol-conformance '{' sil-witness-entry* '}'

SIL將泛型動態(tài)分派所需的信息編碼為witness表.這些信息用于在生成二進制碼時產(chǎn)生運行時分配表(runtime dispatch table).也可以用于對特定通用函數(shù)的SIL優(yōu)化.每個明確的一致性聲明都會產(chǎn)生witness表.通用類型的所有實例共享一個通用witness表.衍生類會繼承基類的witness表.

protocol-conformance ::= normal-protocol-conformance //一般協(xié)議一致性
protocol-conformance ::= 'inherit' '(' protocol-conformance ')'  //繼承關(guān)系的協(xié)議一致性
protocol-conformance ::= 'specialize' '<' substitution* '>'    //通用類型特化的協(xié)議一致性和標(biāo)明類型降級的替換(substitution)
                         '(' protocol-conformance ')'
protocol-conformance ::= 'dependent'
normal-protocol-conformance ::= identifier ':' identifier 'module' identifier

witness的關(guān)鍵在于協(xié)議一致性.它是對于具體類型協(xié)議一致性的唯一標(biāo)識.

  • 一般的協(xié)議一致性通過它們遵守的協(xié)議方法進行命名.屬于該類型或擴展的組件,需要提供遵守協(xié)議方法的聲明,實現(xiàn)方法必須嚴(yán)格和協(xié)議需求一一對應(yīng).
  • 派生類如何遵守從基類繼承的協(xié)議,會體現(xiàn)為繼承協(xié)議一致性(inherited protocol conformance),實現(xiàn)是簡單引用基類的協(xié)議一致性即可.
  • 如果通用類型的實例遵守一個協(xié)議,是通過特化一致性的方式去實現(xiàn)的.將通用參數(shù)和普通一致性進行綁定,將參數(shù)用于通用類型.
    witness table只會直接關(guān)聯(lián)標(biāo)準(zhǔn)一致性.繼承和特定一致性是在標(biāo)準(zhǔn)一致性下的間接引用.
sil-witness-entry ::= 'base_protocol' identifier ':' protocol-conformance
sil-witness-entry ::= 'method' sil-decl-ref ':' sil-function-name
sil-witness-entry ::= 'associated_type' identifier
sil-witness-entry ::= 'associated_type_protocol'
                      '(' identifier ':' identifier ')' ':' protocol-conformance

witness table由以下內(nèi)容構(gòu)成

  • 基協(xié)議項提供的對于協(xié)議一致性的引用,可以用于witness協(xié)議的繼承協(xié)議
  • 方法項將協(xié)議中要求方法映射為SIL中實現(xiàn)了witness類型的方法.每個方法項必須對應(yīng)witness協(xié)議中的要求方法
  • associate type關(guān)聯(lián)類型項將必須實現(xiàn)的協(xié)議方法中的關(guān)聯(lián)類型映射為符合witness的類型.注意witness類似是一個資源級別的swift類型,不是SIL類型(上面分析過SIL類型和swift類型的區(qū)別).關(guān)聯(lián)類型項必須覆蓋witness協(xié)議中的所有強制關(guān)聯(lián)項.
  • 關(guān)聯(lián)類型協(xié)議項將關(guān)聯(lián)類型中的協(xié)議映射為關(guān)聯(lián)類型的協(xié)議一致性.

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市首装,隨后出現(xiàn)的幾起案子杭跪,更是在濱河造成了極大的恐慌,老刑警劉巖桨醋,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喜最,死亡現(xiàn)場離奇詭異庄蹋,居然都是意外死亡,警方通過查閱死者的電腦和手機虫蝶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門能真,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粉铐,你說我怎么就攤上這事蝙泼。” “怎么了汤踏?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵溪胶,是天一觀的道長。 經(jīng)常有香客問我盾饮,道長懒熙,這世上最難降的妖魔是什么普办? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任衔蹲,我火速辦了婚禮,結(jié)果婚禮上橱健,老公的妹妹穿的比我還像新娘沙廉。我一直安慰自己,他們只是感情好珊皿,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布蟋定。 她就那樣靜靜地躺著草添,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屠凶,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天阅畴,我揣著相機與錄音迅耘,去河邊找鬼。 笑死纽哥,一個胖子當(dāng)著我的面吹牛栖秕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播只壳,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼吼句,長吁一口氣:“原來是場噩夢啊……” “哼事格!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起远搪,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤逢捺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棠耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柠新,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡恨憎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓤荔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖点把,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哥童,我是刑警寧澤褒翰,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布优训,位于F島的核電站,受9級特大地震影響撬呢,放射性物質(zhì)發(fā)生泄漏妆兑。R本人自食惡果不足惜毛仪,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腺逛。 院中可真熱鬧衡怀,春花似錦、人聲如沸够委。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潘拨。三九已至,卻和暖如春季蚂,著一層夾襖步出監(jiān)牢的瞬間琅束,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工疯搅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幔欧,地道東北人丽声。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像浴井,于是被迫代替她去往敵國和親霉撵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

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