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 方法可以在运行时被替换。

class-method

The class_method and super_method instructions must reference Swift native methods and always use vtable dispatch.

class_methodsuper_method 指令必须引用 swift 原生方法,并永远使用 vtable(方发表)派发

objc_method

The objc_method and bjc_super_method instructions must reference Objective-C methods (indicated by the foreign marker on a method reference, as in #NSObject.description!foreign).

objc_methodbjc_super_method 指令必须引用 Objective-C 方法(在方法引用上使用 foreign 标记来标识)

code

现有源代码 class.swift 文件

import Foundation

class Foo {
    private func privateFunc() {}
    func normalFunc() { privateFunc() }
    final func finalFunc() {}
    dynamic func dynamicFunc() {}
    @objc func objcFunc() {}
    @objc dynamic func objcDynamicFunc() {}
    @objc final func objcFinalFunc() {}
    @objc dynamic final func objcDynamicFinalFunc() {}
}

extension Foo {
    func extensionFunc() {}
    final func finalExtensionFunc() {}
}

let foo = Foo()

foo.normalFunc()
foo.finalFunc()
foo.objcFunc()
foo.dynamicFunc()
foo.objcDynamicFunc()
foo.objcFinalFunc()
foo.objcDynamicFinalFunc()
foo.extensionFunc()
foo.finalExtensionFunc()

将其编译为 sil

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

得到 class.swift.sil 文件

sil_stage canonical

import Builtin
import Swift
import SwiftShims

import Foundation

class Foo {
  private func privateFunc()
  func normalFunc()
  final func finalFunc()
  dynamic func dynamicFunc()
  @objc func objcFunc()
  @objc dynamic func objcDynamicFunc()
  @objc final func objcFinalFunc()
  @objc dynamic final func objcDynamicFinalFunc()
  @objc private func objcPrivateFunc()
  @objc deinit
  init()
}

extension Foo {
  private func privateExtensionFunc()
  func extensionFunc()
  final func finalExtensionFunc()
  dynamic func dynamicExtensionFunc()
  @objc dynamic func objcExtensionFunc()
  @objc dynamic func objcDynamicExtensionFunc()
  @objc final func objcFinalExtensionFunc()
  @objc dynamic final func objcDynamicFinalExtensionFunc()
}

@_hasStorage @_hasInitialValue let foo: Foo { get }

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

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @$s5class3fooAA3FooCvp             // id: %2
  %3 = global_addr @$s5class3fooAA3FooCvp : $*Foo // users: %47, %44, %41, %38, %35, %32, %29, %26, %23, %20, %17, %14, %11, %8, %7
  %4 = metatype $@thick Foo.Type                  // user: %6
  // function_ref Foo.__allocating_init()
  %5 = function_ref @$s5class3FooCACycfC : $@convention(method) (@thick Foo.Type) -> @owned Foo // user: %6
  %6 = apply %5(%4) : $@convention(method) (@thick Foo.Type) -> @owned Foo // user: %7
  store %6 to %3 : $*Foo                          // id: %7
  %8 = load %3 : $*Foo                            // users: %9, %10
  %9 = class_method %8 : $Foo, #Foo.normalFunc!1 : (Foo) -> () -> (), $@convention(method) (@guaranteed Foo) -> () // user: %10
  %10 = apply %9(%8) : $@convention(method) (@guaranteed Foo) -> ()
  %11 = load %3 : $*Foo                           // user: %13
  // function_ref Foo.finalFunc()
  %12 = function_ref @$s5class3FooC9finalFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %13
  %13 = apply %12(%11) : $@convention(method) (@guaranteed Foo) -> ()
  %14 = load %3 : $*Foo                           // users: %15, %16
  %15 = class_method %14 : $Foo, #Foo.dynamicFunc!1 : (Foo) -> () -> (), $@convention(method) (@guaranteed Foo) -> () // user: %16
  %16 = apply %15(%14) : $@convention(method) (@guaranteed Foo) -> ()
  %17 = load %3 : $*Foo                           // users: %18, %19
  %18 = class_method %17 : $Foo, #Foo.objcFunc!1 : (Foo) -> () -> (), $@convention(method) (@guaranteed Foo) -> () // user: %19
  %19 = apply %18(%17) : $@convention(method) (@guaranteed Foo) -> ()
  %20 = load %3 : $*Foo                           // users: %21, %22
  %21 = objc_method %20 : $Foo, #Foo.objcDynamicFunc!1.foreign : (Foo) -> () -> (), $@convention(objc_method) (Foo) -> () // user: %22
  %22 = apply %21(%20) : $@convention(objc_method) (Foo) -> ()
  %23 = load %3 : $*Foo                           // user: %25
  // function_ref Foo.objcFinalFunc()
  %24 = function_ref @$s5class3FooC13objcFinalFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %25
  %25 = apply %24(%23) : $@convention(method) (@guaranteed Foo) -> ()
  %26 = load %3 : $*Foo                           // users: %27, %28
  %27 = objc_method %26 : $Foo, #Foo.objcDynamicFinalFunc!1.foreign : (Foo) -> () -> (), $@convention(objc_method) (Foo) -> () // user: %28
  %28 = apply %27(%26) : $@convention(objc_method) (Foo) -> ()
  %29 = load %3 : $*Foo                           // user: %31
  // function_ref Foo.extensionFunc()
  %30 = function_ref @$s5class3FooC13extensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %31
  %31 = apply %30(%29) : $@convention(method) (@guaranteed Foo) -> ()
  %32 = load %3 : $*Foo                           // user: %34
  // function_ref Foo.finalExtensionFunc()
  %33 = function_ref @$s5class3FooC18finalExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %34
  %34 = apply %33(%32) : $@convention(method) (@guaranteed Foo) -> ()
  %35 = load %3 : $*Foo                           // user: %37
  // dynamic_function_ref Foo.dynamicExtensionFunc()
  %36 = dynamic_function_ref @$s5class3FooC20dynamicExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %37
  %37 = apply %36(%35) : $@convention(method) (@guaranteed Foo) -> ()
  %38 = load %3 : $*Foo                           // users: %39, %40
  %39 = objc_method %38 : $Foo, #Foo.objcExtensionFunc!1.foreign : (Foo) -> () -> (), $@convention(objc_method) (Foo) -> () // user: %40
  %40 = apply %39(%38) : $@convention(objc_method) (Foo) -> ()
  %41 = load %3 : $*Foo                           // users: %42, %43
  %42 = objc_method %41 : $Foo, #Foo.objcDynamicExtensionFunc!1.foreign : (Foo) -> () -> (), $@convention(objc_method) (Foo) -> () // user: %43
  %43 = apply %42(%41) : $@convention(objc_method) (Foo) -> ()
  %44 = load %3 : $*Foo                           // user: %46
  // function_ref Foo.objcFinalExtensionFunc()
  %45 = function_ref @$s5class3FooC22objcFinalExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %46
  %46 = apply %45(%44) : $@convention(method) (@guaranteed Foo) -> ()
  %47 = load %3 : $*Foo                           // users: %48, %49
  %48 = objc_method %47 : $Foo, #Foo.objcDynamicFinalExtensionFunc!1.foreign : (Foo) -> () -> (), $@convention(objc_method) (Foo) -> () // user: %49
  %49 = apply %48(%47) : $@convention(objc_method) (Foo) -> ()
  %50 = integer_literal $Builtin.Int32, 0         // user: %51
  %51 = struct $Int32 (%50 : $Builtin.Int32)      // user: %52
  return %51 : $Int32                             // id: %52
} // end sil function 'main'

// Foo.privateFunc()
sil private @$s5class3FooC11privateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC11privateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF'

// Foo.normalFunc()
sil hidden @$s5class3FooC10normalFuncyyF : $@convention(method) (@guaranteed Foo) -> () {
// %0                                             // users: %3, %1
bb0(%0 : $Foo):
  debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
  // function_ref Foo.privateFunc()
  %2 = function_ref @$s5class3FooC11privateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> ()
  %4 = tuple ()                                   // user: %5
  return %4 : $()                                 // id: %5
} // end sil function '$s5class3FooC10normalFuncyyF'

// Foo.finalFunc()
sil hidden @$s5class3FooC9finalFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC9finalFuncyyF'

// Foo.dynamicFunc()
sil hidden [dynamically_replacable] @$s5class3FooC11dynamicFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC11dynamicFuncyyF'

// Foo.objcFunc()
sil hidden @$s5class3FooC8objcFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC8objcFuncyyF'

// @objc Foo.objcFunc()
sil hidden [thunk] @$s5class3FooC8objcFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcFunc()
  %2 = function_ref @$s5class3FooC8objcFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC8objcFuncyyFTo'

// Foo.objcDynamicFunc()
sil hidden @$s5class3FooC15objcDynamicFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC15objcDynamicFuncyyF'

// @objc Foo.objcDynamicFunc()
sil hidden [thunk] @$s5class3FooC15objcDynamicFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcDynamicFunc()
  %2 = function_ref @$s5class3FooC15objcDynamicFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC15objcDynamicFuncyyFTo'

// Foo.objcFinalFunc()
sil hidden @$s5class3FooC13objcFinalFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC13objcFinalFuncyyF'

// @objc Foo.objcFinalFunc()
sil hidden [thunk] @$s5class3FooC13objcFinalFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcFinalFunc()
  %2 = function_ref @$s5class3FooC13objcFinalFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC13objcFinalFuncyyFTo'

// Foo.objcDynamicFinalFunc()
sil hidden @$s5class3FooC20objcDynamicFinalFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC20objcDynamicFinalFuncyyF'

// @objc Foo.objcDynamicFinalFunc()
sil hidden [thunk] @$s5class3FooC20objcDynamicFinalFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcDynamicFinalFunc()
  %2 = function_ref @$s5class3FooC20objcDynamicFinalFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC20objcDynamicFinalFuncyyFTo'

// Foo.objcPrivateFunc()
sil private @$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF'

// @objc Foo.objcPrivateFunc()
sil private [thunk] @$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcPrivateFunc()
  %2 = function_ref @$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyFTo'

// Foo.deinit
sil hidden @$s5class3FooCfd : $@convention(method) (@guaranteed Foo) -> @owned Builtin.NativeObject {
// %0                                             // users: %2, %1
bb0(%0 : $Foo):
  debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
  %2 = unchecked_ref_cast %0 : $Foo to $Builtin.NativeObject // user: %3
  return %2 : $Builtin.NativeObject               // id: %3
} // end sil function '$s5class3FooCfd'

// Foo.__deallocating_deinit
sil hidden @$s5class3FooCfD : $@convention(method) (@owned Foo) -> () {
// %0                                             // users: %3, %1
bb0(%0 : $Foo):
  debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
  // function_ref Foo.deinit
  %2 = function_ref @$s5class3FooCfd : $@convention(method) (@guaranteed Foo) -> @owned Builtin.NativeObject // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> @owned Builtin.NativeObject // user: %4
  %4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $Foo // user: %5
  dealloc_ref %4 : $Foo                           // id: %5
  %6 = tuple ()                                   // user: %7
  return %6 : $()                                 // id: %7
} // end sil function '$s5class3FooCfD'

// Foo.__allocating_init()
sil hidden [exact_self_class] @$s5class3FooCACycfC : $@convention(method) (@thick Foo.Type) -> @owned Foo {
bb0(%0 : $@thick Foo.Type):
  %1 = alloc_ref $Foo                             // user: %3
  // function_ref Foo.init()
  %2 = function_ref @$s5class3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo // user: %3
  %3 = apply %2(%1) : $@convention(method) (@owned Foo) -> @owned Foo // user: %4
  return %3 : $Foo                                // id: %4
} // end sil function '$s5class3FooCACycfC'

// Foo.init()
sil hidden @$s5class3FooCACycfc : $@convention(method) (@owned Foo) -> @owned Foo {
// %0                                             // users: %2, %1
bb0(%0 : $Foo):
  debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
  return %0 : $Foo                                // id: %2
} // end sil function '$s5class3FooCACycfc'

// Foo.privateExtensionFunc()
sil private @$s5class3FooC20privateExtensionFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC20privateExtensionFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF'

// Foo.extensionFunc()
sil hidden @$s5class3FooC13extensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () {
// %0                                             // users: %3, %1
bb0(%0 : $Foo):
  debug_value %0 : $Foo, let, name "self", argno 1 // id: %1
  // function_ref Foo.privateExtensionFunc()
  %2 = function_ref @$s5class3FooC20privateExtensionFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> ()
  %4 = tuple ()                                   // user: %5
  return %4 : $()                                 // id: %5
} // end sil function '$s5class3FooC13extensionFuncyyF'

// Foo.finalExtensionFunc()
sil hidden @$s5class3FooC18finalExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC18finalExtensionFuncyyF'

// Foo.dynamicExtensionFunc()
sil hidden [dynamically_replacable] @$s5class3FooC20dynamicExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC20dynamicExtensionFuncyyF'

// Foo.objcExtensionFunc()
sil hidden @$s5class3FooC17objcExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC17objcExtensionFuncyyF'

// @objc Foo.objcExtensionFunc()
sil hidden [thunk] @$s5class3FooC17objcExtensionFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcExtensionFunc()
  %2 = function_ref @$s5class3FooC17objcExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC17objcExtensionFuncyyFTo'

// Foo.objcDynamicExtensionFunc()
sil hidden @$s5class3FooC24objcDynamicExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC24objcDynamicExtensionFuncyyF'

// @objc Foo.objcDynamicExtensionFunc()
sil hidden [thunk] @$s5class3FooC24objcDynamicExtensionFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcDynamicExtensionFunc()
  %2 = function_ref @$s5class3FooC24objcDynamicExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC24objcDynamicExtensionFuncyyFTo'

// Foo.objcFinalExtensionFunc()
sil hidden @$s5class3FooC22objcFinalExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC22objcFinalExtensionFuncyyF'

// @objc Foo.objcFinalExtensionFunc()
sil hidden [thunk] @$s5class3FooC22objcFinalExtensionFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcFinalExtensionFunc()
  %2 = function_ref @$s5class3FooC22objcFinalExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC22objcFinalExtensionFuncyyFTo'

// Foo.objcDynamicFinalExtensionFunc()
sil hidden @$s5class3FooC29objcDynamicFinalExtensionFuncyyF : $@convention(method) (@guaranteed 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 '$s5class3FooC29objcDynamicFinalExtensionFuncyyF'

// @objc Foo.objcDynamicFinalExtensionFunc()
sil hidden [thunk] @$s5class3FooC29objcDynamicFinalExtensionFuncyyFTo : $@convention(objc_method) (Foo) -> () {
// %0                                             // users: %4, %3, %1
bb0(%0 : $Foo):
  strong_retain %0 : $Foo                         // id: %1
  // function_ref Foo.objcDynamicFinalExtensionFunc()
  %2 = function_ref @$s5class3FooC29objcDynamicFinalExtensionFuncyyF : $@convention(method) (@guaranteed Foo) -> () // user: %3
  %3 = apply %2(%0) : $@convention(method) (@guaranteed Foo) -> () // user: %5
  strong_release %0 : $Foo                        // id: %4
  return %3 : $()                                 // id: %5
} // end sil function '$s5class3FooC29objcDynamicFinalExtensionFuncyyFTo'

sil_vtable Foo {
  #Foo.privateFunc!1: (Foo) -> () -> () : @$s5class3FooC11privateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF	// Foo.privateFunc()
  #Foo.normalFunc!1: (Foo) -> () -> () : @$s5class3FooC10normalFuncyyF	// Foo.normalFunc()
  #Foo.dynamicFunc!1: (Foo) -> () -> () : @$s5class3FooC11dynamicFuncyyF	// Foo.dynamicFunc()
  #Foo.objcFunc!1: (Foo) -> () -> () : @$s5class3FooC8objcFuncyyF	// Foo.objcFunc()
  #Foo.objcPrivateFunc!1: (Foo) -> () -> () : @$s5class3FooC15objcPrivateFunc33_6712BA649A8796091338CD63BF3DA51DLLyyF	// Foo.objcPrivateFunc()
  #Foo.init!allocator.1: (Foo.Type) -> () -> Foo : @$s5class3FooCACycfC	// Foo.__allocating_init()
  #Foo.deinit!deallocator.1: @$s5class3FooCfD	// Foo.__deallocating_deinit
}

分析

方法 行号 指令 派发类型
func normalFunc() 50 class_method vtable
private func privateFunc() 117 function_ref direct
final func finalFunc() 54 function_ref direct
dynamic func dynamicFunc() 57 class_method vtable
@objc func objcFunc() 60 class_method vtable
@objc dynamic func objcDynamicFunc() 63 objc_method message
@objc final func objcFinalFunc() 67 function_ref direct
@objc dynamic final func objcDynamicFinalFunc() 70 objc_method message
func extensionFunc() 74 function_ref direct
func privateExtensionFunc() 302 function_ref direct
final func finalExtensionFunc() 78 function_ref direct
dynamic func dynamicExtensionFunc() 82 dynamic_function_ref direct
@objc func objcExtensionFunc() 85 objc_method message
@objc dynamic func objcDynamicExtensionFunc() 88 objc_method message
@objc final func objcFinalExtensionFunc() 92 function_ref direct
@objc dynamic final func objcDynamicFinalExtensionFunc() 95 objc_method message

由27、28行可知,extension 中的 @objc func objcExtensionFunc() {}@objc dynamic func objcDynamicExtensionFunc() {} 效果是一样的,编译器自动添加了 dynamic

虽然private func privateFunc()存在于 vtable 中,由 117 行可知,使用的仍然是静态调用

结论

优先级

@objc dynamic -> message

final -> direct

@objc -> message(extension),vtable(initial declaration)

@objc dynamic > final > @objc

  direct(直接派发) table(方法表派发) message(消息派发)
Class 1. extesion 中没有修饰符的方法。2. 使用 final 修饰的方法(受优先级影响) 类中初始声明的方法(即使有 @objc dynamic 修饰) 1. 所有 @objc dynamic 修饰的方法。2. extension 中使用 @objc 修饰的方法

对于继承自 NSObject 的类,经分析与 Swift 类表现一致,相关代码可在这里找到