SIL与方法派发--值类型

swift 版本

Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)

SIL

function_ref

Creates a reference to a SIL function.

创建一个对 SIL 方法的引用,可以理解为一个指向方法实现的指针

dynamic-function-ref

Creates a reference to a dynamically_replacable SIL function. A dynamically_replacable SIL function can be replaced at runtime.

创建一个对 dynamically_replacable SIL 方法的引用,可以理解为一个指向方法实现的指针。
dynamically_replacable 的 SIL 方法可以在运行时被替换。

code

struct 为例,现有源代码 struct.swift 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Foundation
struct Foo {
func normalFunc() {}
// @objc func objcFunc() {} // @objc can only be used with members of classes, @objc protocols, and concrete extensions of classes
// final func finalFunc() {} // error: only classes and class members may be marked with 'final'

dynamic func dynamicFunc() {}
}

extension Foo {
func extensionFunc() {}
}

let foo = Foo()
foo.normalFunc()
foo.extensionFunc()
foo.dynamicFunc()

将其编译为 sil

1
swiftc -emit-sil -Onone struct.swift > struct.swift.sil

得到 struct.swift.sil 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
sil_stage canonical

import Builtin
import Swift
import SwiftShims

import Foundation

struct Foo {
func normalFunc()
dynamic func dynamicFunc()
init()
}

extension Foo {
func extensionFunc()
}

@_hasStorage @_hasInitialValue let foo: Foo { get }

// foo
sil_global hidden [let] @$s6struct3fooAA3FooVvp : $Foo

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @$s6struct3fooAA3FooVvp // id: %2
%3 = global_addr @$s6struct3fooAA3FooVvp : $*Foo // users: %14, %11, %8, %7
%4 = metatype $@thin Foo.Type // user: %6
// function_ref Foo.init()
%5 = function_ref @$s6struct3FooVACycfC : $@convention(method) (@thin Foo.Type) -> Foo // user: %6
%6 = apply %5(%4) : $@convention(method) (@thin Foo.Type) -> Foo // user: %7
store %6 to %3 : $*Foo // id: %7
%8 = load %3 : $*Foo // user: %10
// function_ref Foo.normalFunc()
%9 = function_ref @$s6struct3FooV10normalFuncyyF : $@convention(method) (Foo) -> () // user: %10
%10 = apply %9(%8) : $@convention(method) (Foo) -> ()
%11 = load %3 : $*Foo // user: %13
// function_ref Foo.extensionFunc()
%12 = function_ref @$s6struct3FooV13extensionFuncyyF : $@convention(method) (Foo) -> () // user: %13
%13 = apply %12(%11) : $@convention(method) (Foo) -> ()
%14 = load %3 : $*Foo // user: %16
// dynamic_function_ref Foo.dynamicFunc()
%15 = dynamic_function_ref @$s6struct3FooV11dynamicFuncyyF : $@convention(method) (Foo) -> () // user: %16
%16 = apply %15(%14) : $@convention(method) (Foo) -> ()
%17 = integer_literal $Builtin.Int32, 0 // user: %18
%18 = struct $Int32 (%17 : $Builtin.Int32) // user: %19
return %18 : $Int32 // id: %19
} // end sil function 'main'

// Foo.normalFunc()
sil hidden @$s6struct3FooV10normalFuncyyF : $@convention(method) (Foo) -> () {
// %0 // user: %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function '$s6struct3FooV10normalFuncyyF'

// Foo.dynamicFunc()
sil hidden [dynamically_replacable] @$s6struct3FooV11dynamicFuncyyF : $@convention(method) (Foo) -> () {
// %0 // user: %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function '$s6struct3FooV11dynamicFuncyyF'

// Foo.init()
sil hidden @$s6struct3FooVACycfC : $@convention(method) (@thin Foo.Type) -> Foo {
bb0(%0 : $@thin Foo.Type):
%1 = alloc_stack $Foo, let, name "self" // user: %3
%2 = struct $Foo () // user: %4
dealloc_stack %1 : $*Foo // id: %3
return %2 : $Foo // id: %4
} // end sil function '$s6struct3FooVACycfC'

// Foo.extensionFunc()
sil hidden @$s6struct3FooV13extensionFuncyyF : $@convention(method) (Foo) -> () {
// %0 // user: %1
bb0(%0 : $Foo):
debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function '$s6struct3FooV13extensionFuncyyF'

分析

方法 行号 指令 派发类型
func normalFunc() 36 function_ref direct
dynamic func dynamicFunc() 40 dynamic_function_ref direct
func extensionFunc() 44 function_ref direct

可以看出,对于值类型的原始方法声明、extension 中的方法声明,使用的都是静态调用的方式来进行方法派发的。

结论

direct(直接派发) table(方法表派发) message(消息派发)
Value Type(值类型) All Methods(所有方法) N/A N/A