Swift编译之SIL(Swift Intermediate Language)

编译过程

  • Parse:从.swift构造 AST(抽象语法树)。
  • Sema:对 AST 进行语义分析,生成格式正确且类型检查完备的 AST。
  • SILGen:从 AST 生成 raw SIL。
  • IRGen:从 canonical SIL 生成 IR。
  • LLVM:LLVM Backend 从优化后的 IR 生成汇编代码或者目标代码。

SIL生成

swift 复制代码
// 将main.swift编译成SIL
swiftc -emit-sil main.swift 
// 将main.swift编译成SIL
swiftc -emit-sil main.swift > main.sil
// 将main.swift编译成SIL的同时还原毫无规则的命名
swiftc -emit-sil main.swift | xcrun swift-demangle > main.sil
// UIKit+x86_64
swiftc -emit-sil -target x86_64-apple-ios17.0.1-simulator -sdk $(xcrun --show-sdk-path --sdk iphonesimulator) ViewController.swift | xcrun swift-demangle > ViewController.sil
// UIKit+arm64
swiftc -emit-sil -target arm64-apple-ios17.0.1-simulator -sdk $(xcrun --show-sdk-path --sdk iphonesimulator) ViewController.swift | xcrun swift-demangle > ViewController.sil
// SwiftUI
swiftc -emit-sil ContentView.swift | xcrun swift-demangle > ContentView.sil

SIL常见语法

  • hidden:同一个 Swift 模块中的对象可见。
  • load A:从 A 中读取数据。
  • store A to B:将 A 中的值存储到 B 中。
  • sil_global:全局变量。
  • alloc_global:开辟全局变量的内存。
  • global_addr:获取全局变量的地址。
  • alloc_stack/dealloc_stack:开辟/销毁栈区内存空间。
  • alloc_box/dealloc_box:开辟/释放堆区内存空间。
  • bb0/bb1 ...:标记代码块。
  • alloc_ref/dealloc_ref:开辟/释放内存。
  • function_ref:获取直接派发方法引用地址。
  • class_method:通过方法表获取方法引用地址。
  • witness_method:通过 Protocol Witness Table(PWT) 获取对应的方法引用地址。
  • objc_method:获取 Objective-C 方法引用地址。
  • apply:调用方法。
  • return:返回值。
  • retain_value/release_value:引用计数 +1/引用计数 -1。
  • metatype:获取元类型。
  • begin_access/end_access:开始/结束访问目标内存。
  • switch_enum:switch 枚举,一般进行判空操作。
  • pointer_to_address:将原始指针转换为地址。
  • br lable:将控制权从当前块转移到其他块,并将进行传值。
  • $:类型标识。
  • %number:寄存器。
  • @方法名:某个方法的名字。
  • @_hasStorage:存储属性。
  • @_hasInitialValue:属性有初始值。
  • @owned:方法接收者负责销毁返回值。
  • @convention(method):Swift 方法的引用。
  • @convention(thin):Swift 方法的引用,但没有特殊的self或者context参数。
  • @convention(thick):Swift 方法的引用,拥有引用计数的上下文对象。
  • @convention(c):C 方法的引用。
  • @convention(objc_method):Objective-C 方法的引用。
  • @convention(block):Objective-C 块的引用。
  • @convention(witness_method):协议方法的引用。

案例

  • 源代码。
swift 复制代码
import Foundation

protocol SomeProtocol {
    func doSomething()
}

@objc class Person: NSObject, SomeProtocol {
    var name = "zhangsan"

    @objc dynamic func say() {
    }

    func doSomething() {
    }
}

extension Person {
    func drink() {
    }
}
  • SIL。
swift 复制代码
// 表示最终的、经过规范化的SIL代码
sil_stage canonical

// 内建模块,提供了一些底层的内建函数和类型,这些函数和类型通常用于Swift编译器生成的代码中,执行一些特定的低级操作
import Builtin
// Swift标准库的模块,提供了Swift语言的核心功能,包括标准类型、集合、字符串处理等
import Swift
// Swift语言的桥接模块,用于处理Swift与其他语言的交互,例如Objective-C
import SwiftShims

import Foundation

protocol SomeProtocol {
    func doSomething()
}

// 使用@_inheritsConvenienceInitializers注解,继承方便的初始化器
// 使用@objc标记,将类导出到Objective-C
@_inheritsConvenienceInitializers @objc class Person: NSObject, SomeProtocol {
    // 使用@_hasStorage标记,表示这个属性有存储
    // 使用@_hasInitialValue标记,表示这个属性有初始值
    @_hasStorage @_hasInitialValue var name: String { get set }
    // 使用@objc dynamic标记,将方法导出到Objective-C,并启用动态派发
    @objc dynamic func say()
    // 没有@objc标记的普通方法
    func doSomething()
    // 使用override dynamic标记,覆盖父类的初始化器并启用动态派发
    override dynamic init()
    // 使用@objc标记的析构器,将析构器导出到Objective-C
    @objc deinit
}

extension Person {
    func drink()
}

// 使用sil指令定义一个名为main的函数,程序的入口点
// main
sil @main: $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
    // 定义基本块bb0,它接受两个参数,一个是Int32,另一个是UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>
    bb0(%0: $Int32, %1: $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
        // 使用integer_literal指令创建一个Int32类型的字面量0
        %2 = integer_literal $Builtin.Int32, 0 // user: %3,user表示这个操作数标记了在用户级别上使用了该值,表示该值在程序的实际执行中被使用了
    // 使用struct指令将上面创建的Int32字面量包装成Int32结构体
    %3 = struct $Int32(%2: $Builtin.Int32) // user: %4
    // 返回创建的Int32结构体,结束main函数
    return %3: $Int32 // id: %4,id表示用于在程序的其他部分引用该值
} // end sil function 'main'

// 使用sil hidden [transparent]指令定义一个隐藏的、透明的函数,表示初始化Person类的name属性的表达式
// sil hidden:表示这个表达式是隐藏的,即不对外部可见
// [transparent]:表示这个表达式是透明的,即不包含额外的控制流或操作
// @variable initialization expression:表示这是一个变量初始化表达式
// of main.Person.name:指明这个表达式是为Person类的name属性进行初始化
// : Swift.String:指定初始化的目标类型是Swift.String
// : $@convention(thin) () -> @owned String:指定了函数的调用约定,这个表达式的类型是一个函数类型,该函数不接受参数 (()),返回一个拥有所有权的String
// variable initialization expression of Person.name
sil hidden[transparent] @variable initialization expression of main.Person.name: Swift.String: $@convention(thin) () -> @owned String {
    bb0:
        // 使用string_literal指令创建一个UTF-8字符串字面量"zhangsan"
        %0 = string_literal utf8 "zhangsan" // user: %5
    // 使用integer_literal指令创建一个Word类型的字面量8,表示UTF-8编码单元的数量
    %1 = integer_literal $Builtin.Word, 8 // user: %5
    // 使用integer_literal指令创建一个Int1类型的字面量-1,表示字符串是否为ASCII编码
    %2 = integer_literal $Builtin.Int1, -1 // user: %5
    // 使用metatype指令获取String类型的元类型
    %3 = metatype $@thin String.Type // user: %5
    // 使用function_ref指令引用String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)构造函数
    // 这个构造函数接受一个指向UTF-8字符串的原始指针、UTF-8编码单元的数量、以及一个表示是否为ASCII的标志
    // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
    %4 = function_ref @Swift.String(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String: $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %5
    // 使用apply指令调用上述构造函数
    %5 = apply %4(%0, %1, %2, %3): $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %6
    // 返回构造函数的结果,即初始化的字符串
    return %5: $String // id: %6
} // end sil function 'variable initialization expression of main.Person.name : Swift.String'

// String类的构造函数init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)的定义
// sil[always_inline][readonly][_semantics "string.makeUTF8"] :这是关于方法行为和优化的一些指令
// [always_inline]:提示编译器尽可能内联这个方法,以提高性能
// [readonly]:表明该方法是只读的,不对传入的参数进行修改
// [_semantics "string.makeUTF8"]:指定了该方法的语义,这对编译器进行进一步的优化和特殊处理
// @Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String:指定了这个方法的Swift类型签名
// String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
sil[always_inline][readonly][_semantics "string.makeUTF8"] @Swift.String(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String: $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String

// 使用sil hidden指令定义Person类的name属性的getter方法
// Person.name.getter
sil hidden @main.Person.name.getter: Swift.String: $@convention(method) (@guaranteed Person) -> @owned String {
    // 基本块bb0,接受一个Person实例作为参数
    // %0 "self"                                      // users: %2, %1
    bb0(%0: $Person):
        // 在调试中,为参数"self"创建一个调试值
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 使用ref_element_addr指令获取Person实例的name属性的地址
    %2 = ref_element_addr %0: $Person, #Person.name // user: %3
    // 使用begin_access指令开始对name属性的读取访问,dynamic表示动态访问
    %3 = begin_access[read][dynamic] %2: $ * String // users: %4, %6
    // 使用load指令加载name属性的值
    %4 = load %3: $ * String // users: %7, %5
    // 使用retain_value指令保留加载的字符串值
    retain_value %4: $String // id: %5
    // 使用end_access指令结束对name属性的读取访问
    end_access %3: $ * String // id: %6
    // 返回加载并保留的字符串值
    return %4: $String // id: %7
} // end sil function 'main.Person.name.getter : Swift.String'

// 使用sil hidden指令定义Person类的name属性的setter方法,接受一个String实例和一个Person实例
// Person.name.setter
sil hidden @main.Person.name.setter: Swift.String: $@convention(method) (@owned String, @guaranteed Person) -> Void {
    // 定义基本块bb0,它接受两个参数,一个是String实例,另一个是Person实例
    // %0 "value"                                     // users: %11, %8, %4, %2
    // %1 "self"                                      // users: %5, %3
    bb0(%0: $String, %1: $Person):
        // 调试信息,标记参数%0为"value",参数%1为"self"
        debug_value %0: $String, let, name "value", argno 1, implicit // id: %2
    debug_value %1: $Person, let, name "self", argno 2, implicit // id: %3
    // 保留String实例,增加其引用计数
    retain_value %0: $String // id: %4
    // 获取Person实例的name属性地址
    %5 = ref_element_addr %1: $Person, #Person.name // user: %6
    // 开始访问name属性,以便进行修改
    %6 = begin_access[modify][dynamic] %5: $ * String // users: %8, %7, %10
    // 加载原始的String实例
    %7 = load %6: $ * String // user: %9
    // 将新的String实例存储到name属性地址
    store %0 to %6: $ * String // id: %8
    // 释放原始的String实例
    release_value %7: $String // id: %9
    // 结束对name属性的访问
    end_access %6: $ * String // id: %10
    // 释放String实例,减少其引用计数
    release_value %0: $String // id: %11
    // 创建一个空元组作为返回值
    %12 = tuple() // user: %13
    // 返回空元组
    return %12: $() // id: %13
} // end sil function 'main.Person.name.setter : Swift.String'

// 使用sil hidden指令定义Person类的name属性的modify方法
// sil hidden:表示这个modify方法是隐藏的,即不对外部可见
// @main.Person.name.modify:指明这个modify方法是Person类的name属性的modify方法
// : Swift.String:指定modify方法的返回类型是Swift.String,这表示modify方法返回属性的当前值
// : $@yield_once:指定了modify方法的调用约定,其中@yield_once表示该方法会产生一次yield modify 方法通常用于实现属性的写时拷贝,在获取属性时会执行一些操作,并在修改时生成一个拷贝
// @convention(method) (@guaranteed Person) -> @yields @inout String:指定modify方法的签名,该方法接受一个Person实例作为参数,返回一个 String,并且产生一个@yield的值,表示写时拷贝的结果 方法使用@inout String表示这是一个写入操作,需要返回一个写入后的值
// Person.name.modify
sil hidden @main.Person.name.modify: Swift.String: $@yield_once @convention(method) (@guaranteed Person) -> @yields @inout String {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // users: %2, %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 获取Person实例的name属性地址
    %2 = ref_element_addr %0: $Person, #Person.name // user: %3
    // 开始访问name属性,以便进行inout修改
    %3 = begin_access[modify][dynamic] %2: $ * String // users: %5, %8, %4
    // 使用yield指令将对name属性的inout访问暂停,并传递name属性的地址
    yield %3: $ * String, resume bb1, unwind bb2 // id: %4

    bb1: // Preds: bb0
        // 结束对name属性的访问
        end_access %3: $ * String // id: %5
    // 创建一个空元组作为返回值
    %6 = tuple() // user: %7
    return %6: $() // id: %7

    bb2: // Preds: bb0
        // 在异常情况下,结束对name属性的访问并执行unwind
        end_access %3: $ * String // id: %8
    unwind // id: %9
} // end sil function 'main.Person.name.modify : Swift.String'

// 使用sil hidden指令定义Person类的say()方法
// Person.say()
sil hidden @main.Person.say() -> Void: $@convention(method) (@guaranteed Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // user: %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 创建一个空元组作为返回值
    %2 = tuple() // user: %3
    // 返回空元组
    return %2: $() // id: %3
} // end sil function 'main.Person.say() -> ()'

// 使用sil private [thunk]指令定义Objective-C中的thunk实现,将@objc修饰的Person.say()映射到Swift中的main.Person.say()方法
// @objc Person.say()
sil private [thunk] @@objc main.Person.say() -> Void: $@convention(objc_method) (Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0                                             // users: %4, %3, %1
    bb0(%0: $Person):
        // 强引用计数+1,保留Person实例
        strong_retain %0: $Person // id: %1
    // 引用Swift中的Person.say()方法
    // function_ref Person.say()
    %2 = function_ref @main.Person.say() -> Void: $@convention(method) (@guaranteed Person) -> Void // user: %3
    // 调用Swift中的Person.say()方法
    %3 = apply %2(%0): $@convention(method) (@guaranteed Person) -> Void // user: %5
    // 强引用计数-1,释放Person实例
    strong_release %0: $Person // id: %4
    // 返回Swift方法的结果
    return %3: $() // id: %5
} // end sil function '@objc main.Person.say() -> ()'

// 使用sil hidden指令定义Person类的doSomething()方法
// Person.doSomething()
sil hidden @main.Person.doSomething() -> Void: $@convention(method) (@guaranteed Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // user: %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 创建一个空元组作为返回值
    %2 = tuple() // user: %3
    // 返回空元组
    return %2: $() // id: %3
} // end sil function 'main.Person.doSomething() -> ()'

// 使用sil hidden指令定义Person类的__allocating_init()方法,是一个指定初始化器
// (@thick Person.Type):表示这个方法接受一个Person类型的元类型参数,即类本身的类型
// -> @owned Person:表示这个方法返回一个拥有所有权的Person实例
// Person.__allocating_init()
sil hidden @main.Person.__allocating_init() -> main.Person: $@convention(method) (@thick Person.Type) -> @owned Person {
    // 定义基本块bb0,它接受一个Person类型的元类型作为参数
    // %0 "$metatype"                                 // user: %1
    bb0(%0: $@thick Person.Type):
        // 将thick元类型转换为对应的Objective-C元类型
        %1 = thick_to_objc_metatype %0: $@thick Person.Type to $@objc_metatype Person.Type // user: %2
    // 使用alloc_ref_dynamic指令分配Person实例
    %2 = alloc_ref_dynamic[objc] %1: $@objc_metatype Person.Type, $Person // users: %3, %4
    // 使用objc_method指令调用Objective-C中的初始化器init
    %3 = objc_method %2: $Person, #Person.init!initializer.foreign: (Person.Type) -> () -> Person, $@convention(objc_method) (@owned Person) -> @owned Person // user: %4
    // 调用init初始化器
    %4 = apply %3(%2): $@convention(objc_method) (@owned Person) -> @owned Person // user: %5
    // 返回初始化后的Person实例
    return %4: $Person // id: %5
} // end sil function 'main.Person.__allocating_init() -> main.Person'

// 使用sil shared [transparent] [thunk]指令定义动态初始化器的thunk实现
// sil shared:表示这个初始化方法是共享的,即可能被其他模块访问
// [transparent]:表示这个初始化方法是透明的,即没有额外的控制流或操作
// [thunk]:表示这是一个动态分发的方法,可能涉及到动态派发
// @dynamic main.Person.init():指明这个方法是Person类的初始化方法
// -> main.Person:表示这个初始化方法的返回类型是Person类的实例
// dynamic Person.init()
sil shared[transparent][thunk] @dynamic main.Person() -> main.Person: $@convention(method) (@owned Person) -> @owned Person {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // users: %2, %1
    bb0(%0: $Person):
        // 使用objc_method指令调用Objective-C中的初始化器init
        %1 = objc_method %0: $Person, #Person.init!initializer.foreign: (Person.Type) -> () -> Person, $@convention(objc_method) (@owned Person) -> @owned Person // user: %2
    // 调用init初始化器
    %2 = apply %1(%0): $@convention(objc_method) (@owned Person) -> @owned Person // user: %3
    // 返回初始化后的Person实例
    return %2: $Person // id: %3
} // end sil function 'dynamic main.Person.init() -> main.Person'

// 使用sil hidden指令定义Person类的init()方法
// Person.init()
sil hidden @main.Person() -> main.Person: $@convention(method) (@owned Person) -> @owned Person {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // users: %12, %4, %3, %2
    bb0(%0: $Person):
        // 分配一个Person实例的栈空间
        %1 = alloc_stack[lexical] $Person, let, name "self", implicit // users: %20, %13, %3, %21, %22
    // 强引用计数+1,保留Person实例
    strong_retain %0: $Person // id: %2
    // 将Person实例存储到栈空间
    store %0 to %1: $ * Person // id: %3
    // 获取Person实例的name属性地址
    %4 = ref_element_addr %0: $Person, #Person.name // user: %11
    // 创建String实例,初始化为"zhangsan"
    %5 = string_literal utf8 "zhangsan" // user: %10
    %6 = integer_literal $Builtin.Word, 8 // user: %10
    %7 = integer_literal $Builtin.Int1, -1 // user: %10
    %8 = metatype $@thin String.Type // user: %10
    // 获取并调用String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)方法
    // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
    %9 = function_ref @Swift.String(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String: $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %10
    %10 = apply %9(%5, %6, %7, %8): $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %11
    // 将创建的String实例存储到name属性地址
    store %10 to %4: $ * String // id: %11
    // 强引用计数-1,释放Person实例
    strong_release %0: $Person // id: %12
    // 加载栈空间中的Person实例
    %13 = load %1: $ * Person // user: %14
    // 对Person实例进行强转换为NSObject
    %14 = upcast %13: $Person to $NSObject // users: %15, %17
    // 调用NSObject的init方法
    %15 = unchecked_ref_cast %14: $NSObject to $Person // user: %16
    %16 = objc_super_method %15: $Person, #NSObject.init!initializer.foreign: (NSObject.Type) -> () -> NSObject, $@convention(objc_method) (@owned NSObject) -> @owned NSObject // user: %17
    %17 = apply %16(%14): $@convention(objc_method) (@owned NSObject) -> @owned NSObject // user: %18
    // 对结果进行强转换回Person类型
    %18 = unchecked_ref_cast %17: $NSObject to $Person // users: %20, %23, %19
    // 强引用计数+1,保留Person实例
    strong_retain %18: $Person // id: %19
    // 将Person实例存储到栈空间
    store %18 to %1: $ * Person // id: %20
    // 销毁栈空间中的Person实例
    destroy_addr %1: $ * Person // id: %21
    // 释放栈空间
    dealloc_stack %1: $ * Person // id: %22
    // 返回初始化后的Person实例
    return %18: $Person // id: %23
} // end sil function 'main.Person.init() -> main.Person'

// 使用sil private [thunk]指令定义Objective-C中的thunk实现,将@objc修饰的Person.init()映射到Swift中的main.Person.init()方法
// @@objc main.Person.init():指明这个协议见证是为Person类的Objective-C初始化方法
// @convention(objc_method):表示这是一个Objective-C方法
// @objc Person.init()
sil private [thunk] @@objc main.Person() -> main.Person: $@convention(objc_method) (@owned Person) -> @owned Person {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0                                             // user: %2
    bb0(%0: $Person):
        // 引用Swift中的Person.init()方法
        // function_ref Person.init()
        %1 = function_ref @main.Person() -> main.Person: $@convention(method) (@owned Person) -> @owned Person // user: %2
    // 调用并返回对象
    %2 = apply %1(%0): $@convention(method) (@owned Person) -> @owned Person // user: %3
    return %2: $Person // id: %3
} // end sil function '@objc main.Person.init() -> main.Person'

// 使用sil hidden指令定义Person类的__deallocating_deinit方法,是一个析构器
// Person.__deallocating_deinit
sil hidden @main.Person.__deallocating_deinit: $@convention(method) (@owned Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // users: %3, %2, %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 使用objc_super_method指令调用NSObject的析构器deinit
    %2 = objc_super_method %0: $Person, #NSObject.deinit!deallocator.foreign: (NSObject) -> () -> Void, $@convention(objc_method) (NSObject) -> Void // user: %4
    // 对Person实例进行强转换为NSObject类型
    %3 = upcast %0: $Person to $NSObject // user: %4
    // 调用NSObject的析构器deinit
    %4 = apply %2(%3): $@convention(objc_method) (NSObject) -> Void
    // 创建一个空元组作为返回值
    %5 = tuple() // user: %6
    // 返回空元组
    return %5: $() // id: %6
} // end sil function 'main.Person.__deallocating_deinit'

// 使用sil hidden @@objc指令定义Objective-C中的实例变量销毁方法__ivar_destroyer
// @objc Person.__ivar_destroyer
sil hidden @@objc main.Person.__ivar_destroyer: $@convention(objc_method) (Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // users: %2, %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 获取Person实例的name属性地址
    %2 = ref_element_addr %0: $Person, #Person.name // user: %3
    // 开始访问name属性,指定为deinit操作
    %3 = begin_access[deinit][static] %2: $ * String // users: %5, %4
    // 销毁name属性的内存
    destroy_addr %3: $ * String // id: %4
    // 结束对name属性的访问
    end_access %3: $ * String // id: %5
    // 创建一个空元组作为返回值
    %6 = tuple() // user: %7
    // 返回空元组
    return %6: $() // id: %7
} // end sil function '@objc main.Person.__ivar_destroyer'

// 使用sil private [transparent] [thunk]指令定义协议witness实现,实现SomeProtocol协议的doSomething()方法
// sil private:表示这个协议见证是私有的,即不对外部可见
// [transparent]:表示这个协议见证是透明的,即没有额外的控制流或操作
// [thunk]:表示这是一个动态分发的协议见证,可能涉及到动态派发
// @protocol witness for main.SomeProtocol.doSomething() -> ():指定了这个协议见证是为SomeProtocol协议的doSomething()方法
// in conformance main.Person : main.SomeProtocol in main:指明这个协议见证是在Person类对SomeProtocol协议的遵循中
// @convention(witness_method: SomeProtocol):表示这是一个协议方法的见证
// (@in_guaranteed Person):表示这个方法接受一个在整个调用期间保证有效的Person实例作为参数
// -> ():表示这个方法没有返回值
// protocol witness for SomeProtocol.doSomething() in conformance Person
sil private [transparent][thunk] @protocol witness for main.SomeProtocol.doSomething() in conformance main.Person: main.SomeProtocol in main: $@convention(witness_method: SomeProtocol) (@in_guaranteed Person) -> Void {
    // 定义基本块bb0,它接受一个指向Person实例的指针作为参数
    // %0                                             // user: %1
    bb0(%0: $ * Person):
        // 加载Person实例
        %1 = load %0: $ * Person // users: %2, %3
    // 获取并调用Person实例的doSomething()方法
    %2 = class_method %1: $Person, #Person.doSomething: (Person) -> () -> Void, $@convention(method) (@guaranteed Person) -> Void // user: %3
    %3 = apply %2(%1): $@convention(method) (@guaranteed Person) -> Void
    // 创建一个空元组作为返回值
    %4 = tuple() // user: %5
    // 返回空元组
    return %4: $() // id: %5
} // end sil function 'protocol witness for main.SomeProtocol.doSomething() -> () in conformance main.Person : main.SomeProtocol in main'

// 使用sil hidden指令定义Person类的drink()方法
// sil hidden:这表示该函数是隐藏的,即它不会在模块之外可见
// @main.Person.drink():这是函数的完全限定名称,指明了该函数属于main模块中的Person类的drink()方法
// -> ():表示函数的返回类型为空元组,即函数不返回任何值
// : $@convention(method):这部分指定了函数的调用约定,表明这是一个方法,在Swift中,方法调用与函数调用有一些不同之处,例如它们使用隐式的self参数
// (@guaranteed Person) -> ():这是函数的参数列表@guaranteed是一个生命周期修饰符,表示参数Person在整个函数调用期间都是有效的Person 是参数的类型,表示该方法在调用时需要一个 Person 实例
// Person.drink()
sil hidden @main.Person.drink() -> Void: $@convention(method) (@guaranteed Person) -> Void {
    // 定义基本块bb0,它接受一个Person实例作为参数
    // %0 "self"                                      // user: %1
    bb0(%0: $Person):
        // 调试信息,标记参数%0为"self"
        // implicit表示这是一个隐式的变量,它表示这个变量并不是由程序员显式创建的,而是由编译器生成
        debug_value %0: $Person, let, name "self", argno 1, implicit // id: %1
    // 创建一个空元组作为返回值
    %2 = tuple() // user: %3
    // 返回空元组
    return %2: $() // id: %3
} // end sil function 'main.Person.drink() -> ()'

// vtable
// Person中的方法
sil_vtable Person {
    #Person.name!getter: (Person) -> () -> String: @main.Person.name.getter: Swift.String // Person.name.getter
    #Person.name!setter: (Person) -> (String) -> Void: @main.Person.name.setter: Swift.String // Person.name.setter
    #Person.name!modify: (Person) -> () -> Void: @main.Person.name.modify: Swift.String // Person.name.modify
    #Person.doSomething: (Person) -> () -> Void: @main.Person.doSomething() -> Void // Person.doSomething()
    #Person.deinit!deallocator: @main.Person.__deallocating_deinit // Person.__deallocating_deinit
}

// witness_table
// hidden:表示这个协议见证表是隐藏的,即不对外部可见。
// Person: SomeProtocol:指明这个协议见证表是为Person类对SomeProtocol协议的遵循
// module main:指定了这个协议见证表所属的模块为main 
sil_witness_table hidden Person: SomeProtocol module main {
    method #SomeProtocol.doSomething: <Self where Self: SomeProtocol>(Self) -> () -> Void: @protocol witness for main.SomeProtocol.doSomething() in conformance main.Person: main.SomeProtocol in main // protocol witness for SomeProtocol.doSomething() in conformance Person
}

// 文件映射关系
// Mappings from '#fileID' to '#filePath':
//   'main/main.swift' => 'main.swift'

参考

  1. Swift Intermediate Language (SIL)
  2. GroffLattner-SILHighLevelIR
相关推荐
良技漫谈2 天前
Rust移动开发:Rust在iOS端集成使用介绍
后端·程序人生·ios·rust·objective-c·swift
KeithTsui2 天前
ZFC in LEAN 之 前集的等价关系(Equivalence on Pre-set)详解
开发语言·其他·算法·binder·swift
袁代码2 天前
Swift 开发教程系列 - 第4章:函数与闭包
ios·swift·ios开发
安泽13143 天前
高德地图美食
开发语言·swift·美食
袁代码4 天前
Swift 开发教程系列 - 第2章:Swift 基础语法
swift·ios开发·基础教程
袁代码4 天前
Swift 开发教程系列 - 第1章:Swift 简介与开发环境配置
swift·ios开发·基础教程
孚亭4 天前
一些swift问题
swift
莫问alicia4 天前
echarts 实现3D饼状图 加 label标签显示
前端·3d·echarts·swift
uiop_uiop_uiop7 天前
iOS Swift5算法恢复——HMAC
ios·iphone·swift
東三城8 天前
【ios】---SwiftUI开发从入门到放弃
ios·swiftui·swift·1024程序员节