SIL与方法派发——Class
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_methodandsuper_methodinstructions must reference Swift native methods and always use vtable dispatch.
class_method 和 super_method 指令必须引用 swift 原生方法,并永远使用 vtable(方发表)派发
objc_method
The
objc_methodandbjc_super_methodinstructions must reference Objective-C methods (indicated by the foreign marker on a method reference, as in #NSObject.description!foreign).
objc_method 和 bjc_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 类表现一致,相关代码可在这里找到