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 文件

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

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

得到 struct.swift.sil 文件

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