Swift 是一門靜態(tài)語言铜异,在 Swift 中聲明的方法和屬性靜態(tài)編譯期就確定了的,并且Swift具有更靈活的高級特性秸架,協(xié)議,泛型东抹,方法重載,值引用等食茎,所以其與OC運(yùn)行時(shí)動(dòng)態(tài)消息派發(fā)不同附迷,需要支持靜態(tài)派發(fā)以及動(dòng)態(tài)派發(fā),目前的這些特性Clang并不能完全支持壹哺。
因此蘋果另外實(shí)現(xiàn)了一套 Swift() 作為Swift的編譯前端,由于其語言特性管宵,反而有更多的優(yōu)化空間截珍。
其使用SIL作為前端中間表示層,與IR差異很大箩朴,大致體現(xiàn)在:
- 在編譯期完全確定的調(diào)用關(guān)系會采用靜態(tài)派發(fā)岗喉,即在可執(zhí)行文件中直接指定方法實(shí)現(xiàn)的內(nèi)存地址的指針,在運(yùn)行時(shí)直接通過指針調(diào)用
- 在編譯期間無法確定最終合適的操作時(shí)炸庞,則會執(zhí)行動(dòng)態(tài)派發(fā)钱床。Swift又不完全同于C++的方式,其除了支持繼承使用的虛函數(shù)表vtable埠居,還加入了支持面向協(xié)議編程的witness table
- 通過dynamic關(guān)鍵字對方法標(biāo)記查牌,使用OC的運(yùn)行時(shí)機(jī)制
- 由于支持函數(shù)重載,也就引出了name mangling(名字修飾)機(jī)制纸颜,其目的是給同名的重載函數(shù)不同的簽名
- ...
1. Clang vs Swift():
Clang
- Wide abstraction gap between source and LLVM IR
- IR isn't suitable for source-level analysis
- CFG lacks fidelity
- CFG is off the hot path
- Duplicated effort in CFG and IR lowering
Swift
- Higher-level language
- Move more of the language into code
- Protocol-based generics
- Safe language
- Uninitialized vars, unreachable code should be compiler errors
- Bounds and overflow checks
2. V-Table
常見的編譯型語言的動(dòng)態(tài)派發(fā)方式绎橘,編譯器層使用一個(gè)表格結(jié)構(gòu)來存儲類型聲明中的每一個(gè)函數(shù)指針。C++中稱之為虛函數(shù)表VTable称鳞,也是其支持多態(tài)的基礎(chǔ)涮较。
在Swift中,擁有繼承關(guān)系的Class采用此種方式冈止,即每一個(gè)類會維護(hù)一個(gè)函數(shù)表,該表會記錄該類中所有的函數(shù)指針:
- 由父類繼承而來的方法執(zhí)行地址靶瘸。
- 如果子類重寫父類方法毛肋,表中會保存被重載之后的函數(shù)。
- 子類新增的函數(shù)會加入到表的末尾屋剑。
然后在程序運(yùn)行期間查表執(zhí)行具體實(shí)現(xiàn)润匙。
3. Protocol Witness Table
因?yàn)閰f(xié)議不一定具有繼承關(guān)系,所以其創(chuàng)建了Protocol Witness Table唉匾。大致實(shí)現(xiàn)為:Swift會為每一個(gè)實(shí)現(xiàn)了該協(xié)議的對象生成一個(gè)大小一致的結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體被稱為Existenial Container
巍膘,它內(nèi)部包含PWT,表中存儲著一組函數(shù)的執(zhí)行地址峡懈,而表中的每一個(gè)條目指向了符合該協(xié)議的類型信息。該結(jié)構(gòu)體中還保留了三個(gè)字長的valueBuffer用來存儲數(shù)據(jù)成員荚恶。
4. SIL
SIL是一種SSA形式的IR磷支,具有高級語義信息谒撼,旨在實(shí)現(xiàn)Swift編程語言雾狈。 SIL適用于以下用例:
- 一組有保證的高級優(yōu)化,可為運(yùn)行時(shí)和診斷行為提供可預(yù)測的基準(zhǔn)善榛。
- 診斷數(shù)據(jù)流分析過程可滿足Swift語言要求,例如變量和構(gòu)造函數(shù)的確定性初始化堪澎,代碼可訪問性味滞,開關(guān)覆蓋率樱蛤。
- 高級優(yōu)化過程剑鞍,包括保留/釋放優(yōu)化,動(dòng)態(tài)方法去虛擬化便脊,閉包內(nèi)聯(lián),將堆分配提升為堆棧分配哪痰,將堆分配提升為SSA寄存器,將標(biāo)量替換為標(biāo)量(將標(biāo)量分配拆分為多個(gè)較小的標(biāo)量)和通用函數(shù)實(shí)例化晌杰。
- 一種穩(wěn)定的分發(fā)格式跷睦,可用于分發(fā)帶有Swift庫模塊的“易碎”的內(nèi)聯(lián)代碼或通用代碼,并將其優(yōu)化為客戶端二進(jìn)制文件肋演。
與LLVM IR相比,SIL是一種通常與目標(biāo)無關(guān)的格式表示形式爹殊,可用于代碼分發(fā),但它也可以像LLVM一樣表示特定于目標(biāo)的概念梗夸。
- 完全代表程序語義
- 專為代碼生成和分析而設(shè)計(jì)
- 位于編譯器管道的熱路徑上
- 修復(fù)了源代碼和LLVM之間的抽象鴻溝
在較高的層次上,Swift編譯器遵循嚴(yán)格的管道架構(gòu):
- Parse模塊從Swift源代碼構(gòu)造AST称簿。
- Sema模塊對AST進(jìn)行類型檢查惰帽,并使用類型信息對其進(jìn)行注釋父虑。
- SILGen模塊從AST生成raw SIL。
- 在原始SIL上運(yùn)行一系列“保證的優(yōu)化Pass”和“診斷Pass”士嚎,以執(zhí)行優(yōu)化并發(fā)出特定于語言的診斷信息。即使在-Onone上爵嗅,它們也始終運(yùn)行笨蚁,并生成規(guī)范SIL睹晒。
- 常規(guī)SIL 優(yōu)化Pass(可選)在規(guī)范的SIL上運(yùn)行括细,以提高生成的可執(zhí)行文件的性能。這些是由優(yōu)化級別啟用和控制的锉试,而不是在-Onone上運(yùn)行览濒。
- IRGen將規(guī)范SIL降低為LLVM IR拖云。
- LLVM后端(可選)使用LLVM優(yōu)化应又,運(yùn)行LLVM代碼生成器并產(chǎn)生二進(jìn)制代碼。
5. SILGen
SILGen通過遍歷經(jīng)過類型檢查的Swift AST來生成“原始SIL”丁频。 SILGen發(fā)出的SIL形式具有以下特性:
- 變量通過加載和存儲可變存儲器位置來表示,而不是采用嚴(yán)格的SSA形式席里。 這類似于前端(如Clang)發(fā)出的初始“alloca”大量的LLVM IR。 但是改基,在最普通的情況下咖为,Swift將變量表示為引用計(jì)數(shù)的“boxes”,可以將其保留躁染,釋放并捕獲到閉包中。
- 尚未執(zhí)行數(shù)據(jù)流要求我衬,例如最終分配饰恕,函數(shù)返回挠羔,開關(guān)覆蓋率(TBD)等埋嵌。
-
transparent
功能優(yōu)化尚未實(shí)現(xiàn)。
這些屬性通過后續(xù)保證的優(yōu)化和診斷遍歷得到解決范舀,這些遍歷始終針對原始SIL運(yùn)行俐银。
6. General Optimization Passes
SIL捕獲特定語言的類型信息,從而可以實(shí)現(xiàn)在LLVM IR上難以執(zhí)行的高級優(yōu)化捶惜。
- Generic Specialization 分析對泛型函數(shù)的專門調(diào)用,并生成函數(shù)的新的指定版本汽久。然后,它將泛型的所有指定用法重寫為對指定功能的直接調(diào)用景醇。
- 給定類型的 Witness and VTable Devirtualization 從類的vtable或類型見證表中查找關(guān)聯(lián)的方法,并將間接虛擬調(diào)用替換為對映射函數(shù)的調(diào)用吧寺。
- Performance Inlining
- Reference Counting Optimizations
- Memory Promotion/Optimizations
- High-level domain specific optimizations Swift編譯器在基礎(chǔ)的Swift容器(例如Array或String)上實(shí)現(xiàn)了高級優(yōu)化散劫。特定于域的優(yōu)化需要在標(biāo)準(zhǔn)庫和優(yōu)化器之間定義接口。更多細(xì)節(jié)可以查看:HighLevelSILOptimizations
如下代碼為swift實(shí)現(xiàn)代碼在SIL下的展現(xiàn)形式:
sil_stage canonical
import Swift
//定義SIL函數(shù)使用的類型获搏。
struct Point {
var x:Double
var y:Double
}
class Button {
func onClick()
func onMouseDown()
func onMouseUp()
}
//聲明一個(gè)Swift函數(shù)。主體被SIL忽略纬乍。
func taxicabNorm(_ a:Point)-> Double {
return a.x + a.y
}
//定義SIL函數(shù)裸卫。
//名稱@_T5norms11taxicabNormfT1aV5norms5Point_Sd是 taxicabNorm Swift函數(shù)的錯(cuò)誤名稱。
sil @ _T5norms11taxicabNormfT1aV5norms5Point_Sd:$(Point)-> Double {
bb0(%0:$ Point):
// func Swift彼城。+(Double退个,Double)-> Double
%1 = function_ref @ _Tsoi1pfTSdSd_Sd
%2 = struct_extract%0:$ Point,#Point.x
%3 = struct_extract%0:$ Point语盈,#Point.y
%4 = apply%1(%2,%3):$(Double代嗤,Double)-> Double
return%4:Double
}
//定義SIL vtable缠借。匹配動(dòng)態(tài)分派的方法
//標(biāo)識與其已知靜態(tài)類類型的實(shí)現(xiàn)相匹配。
sil_vtable Button {
#Button.onClick泼返!1:@ _TC5norms6Button7onClickfS0_FT_T_
#Button.onMouseDown!1:@ _TC5norms6Button11onMouseDownfS0_FT_T_
#Button.onMouseUp渠鸽!1:@ _TC5norms6Button9onMouseUpfS0_FT_T_
}