slidenumber: true autoscale: true
- omochimetaru
- アイコン→
- わいわいswiftcでしばしば登壇
SIL1
-
Swift intermediate language
-
SILコードにはSwiftコードよりも具体的な挙動が書かれている
-
暗黙の型変換
-
参照カウントの増減
-
メソッドの呼び出し
func intToIntOptional(x: Int) -> Int? {
return x
}
- Swift的にはそのままreturnしているが、CPUにとっては
Int
からInt?
への変換をしている。
- swiftcコマンドでSILを出力する
$ swiftc -emit-sil -parse-as-library code01.swift
sil_stage canonical
import Builtin
import Swift
import SwiftShims
func intToIntOptional(x: Int) -> Int?
// intToIntOptional(x:)
sil hidden @$s6code0116intToIntOptional1xSiSgSi_tF : $@convention(thin) (Int) -> Optional<Int> {
// %0 // users: %2, %1
bb0(%0 : $Int):
debug_value %0 : $Int, let, name "x", argno 1 // id: %1
%2 = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int // user: %3
return %2 : $Optional<Int> // id: %3
} // end sil function '$s6code0116intToIntOptional1xSiSgSi_tF'
Mangling2
// module: code01
func intToIntOptional(x: Int) -> Int?
↓
$s6code0116intToIntOptional1xSiSgSi_tF
-
モジュール名や型名を混ぜ込んだ(mangle)名前を作る
-
swift demangleコマンドで展開できる
$ swift demangle '$s6code0116intToIntOptional1xSiSgSi_tF'
$s6code0116intToIntOptional1xSiSgSi_tF
---> code01.intToIntOptional(x: Swift.Int) -> Swift.Int?
$s6code0116intToIntOptional1xSiSgSi_tF
$s: Swift5
6: 6文字の単語
code01
16: 16文字の単語
intToIntOptional
1: 1文字の単語
x
Si: Int
Sg: Optional
Si: Int
_: リストの区切り
t: タプル
F: 関数
[.code-highlight: 1-8]
// intToIntOptional(x:)
sil hidden @$s6code0116intToIntOptional1xSiSgSi_tF : $@convention(thin) (Int) -> Optional<Int> {
// %0 // users: %2, %1
bb0(%0 : $Int):
debug_value %0 : $Int, let, name "x", argno 1 // id: %1
%2 = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int // user: %3
return %2 : $Optional<Int> // id: %3
} // end sil function '$s6code0116intToIntOptional1xSiSgSi_tF'
[.code-highlight: 6]
// intToIntOptional(x:)
sil hidden @$s6code0116intToIntOptional1xSiSgSi_tF : $@convention(thin) (Int) -> Optional<Int> {
// %0 // users: %2, %1
bb0(%0 : $Int):
debug_value %0 : $Int, let, name "x", argno 1 // id: %1
%2 = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int // user: %3
return %2 : $Optional<Int> // id: %3
} // end sil function '$s6code0116intToIntOptional1xSiSgSi_tF'
%2 = enum $Optional<Int>, #Optional.some!enumelt.1, %0 : $Int // user: %3
%2 =: 結果を%2に代入
enum: enumの値を構築
$Optional<Int>: 型はOptional<Int>
$Optional.some!enumelt.1: caseはsome
%0: associated valueは%0
: $Int: $0の型はInt
//: コメント
user: %3: 結果は命令%3で使う
- Swiftはクラスインスタンスのメモリ管理に参照カウントを使う
- 初期値1
- 0になったら解放
- 変数代入: 古いインスタンスはrelease(-1)
- 変数破棄: 所持するインスタンスをrelease
- 関数呼び出し: 実引数をretain(+1), 呼び出し後にrelease
class Cat {}
func useCat(_ cat: Cat) { }
func changeCat(_ cat: Cat) -> Cat {
return Cat()
}
func main() {
var cat = Cat()
useCat(cat)
cat = changeCat(cat)
}
func main() {
// 初期化
var cat = Cat()
// 呼び出し前に引数のretain
useCat(cat)
// 呼び出し後に引数のrelease
// 呼び出し前に引数のretain
cat = changeCat(cat)
// 呼び出し後に引数のrelease
// 古い値をrelease
// 変数の値をrelease
}
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
[.code-highlight: 4]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
- 変数
cat
を生成(%0
)
[.code-highlight: 28-29]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
- 変数
cat
(%0
)を解放
[.code-highlight: 6-9]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
Cat.init
の呼び出し(%3
)、変数cat
(%0
)に保存
[.code-highlight: 13-15]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
useCat
の呼び出しで%3
を渡す
[.code-highlight: 11, 16]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
useCat
の呼び出し前後で%3
をretain, release
[.code-highlight: 20-22]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
changeCat
の呼び出し(%15
)、引数に%3
[.code-highlight: 18, 23]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
changeCat
の呼び出し前後で%3
をretain, release
[.code-highlight: 25-26]
// main()
sil hidden @$s6code024mainyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Cat, var, name "cat" // users: %4, %22, %21, %5, %11, %17
%1 = metatype $@thick Cat.Type // user: %3
// function_ref Cat.__allocating_init()
%2 = function_ref @$s6code023CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %3
%3 = apply %2(%1) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %19, %12, %15, %16, %6, %9, %10, %4
store %3 to %0 : $*Cat // id: %4
%5 = begin_access [read] [static] %0 : $*Cat // user: %7
strong_retain %3 : $Cat // id: %6
end_access %5 : $*Cat // id: %7
// function_ref useCat(_:)
%8 = function_ref @$s6code026useCatyyAA0C0CF : $@convention(thin) (@guaranteed Cat) -> () // user: %9
%9 = apply %8(%3) : $@convention(thin) (@guaranteed Cat) -> ()
strong_release %3 : $Cat // id: %10
%11 = begin_access [read] [static] %0 : $*Cat // user: %13
strong_retain %3 : $Cat // id: %12
end_access %11 : $*Cat // id: %13
// function_ref changeCat(_:)
%14 = function_ref @$s6code029changeCatyAA0C0CADF : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %15
%15 = apply %14(%3) : $@convention(thin) (@guaranteed Cat) -> @owned Cat // user: %18
strong_release %3 : $Cat // id: %16
%17 = begin_access [modify] [static] %0 : $*Cat // users: %18, %20
store %15 to %17 : $*Cat // id: %18
strong_release %3 : $Cat // id: %19
end_access %17 : $*Cat // id: %20
destroy_addr %0 : $*Cat // id: %21
dealloc_stack %0 : $*Cat // id: %22
%23 = tuple () // user: %24
return %23 : $() // id: %24
} // end sil function '$s6code024mainyyF'
changeCat
の結果(%15
)を変数cat
(%17
=%0
)に代入、古い値(%3
)をrelease
- Swift Forum: Default Protocol Implementation Inheritance Behaviour - The current situation and what/if anything should be done about it 3 2019/08/20
-
定期的に掘り返される話題
-
この投稿でもイシューチケット4 2015/12/7 への言及あり
protocol P {
func f()
}
extension P {
func f() { print("P.f") }
}
class A: P {
func f() { print("A.f") }
}
class B: A {
override func f() { print("B.f") }
}
class C: P {
}
class D: C {
func f() { print("D.f") }
}
func main() {
A().f() // A.f
B().f() // B.f
(B() as A).f() // B.f
C().f() // P.f
D().f() // D.f
(D() as C).f() // P.f
}
main()
-
BはAを継承しているのだから、Bのfをそのまま呼んでも、Aにアップキャストしてから呼んでも同じ🙂
-
DはCを継承しているのに、Dのfをそのまま呼ぶのと、Cにアップキャストしてから呼ぶので結果が違う😲
-
A.fとB.fはクラスメソッド呼び出しなので、オーバーライドされた実装が呼ばれる
-
C.fはwitnessメソッド呼び出し、D.fはクラスメソッド呼び出しなので、オーバーライド関係はない
-
クラスメソッド呼び出し: あるクラスに対応するvtableからメソッドを引く
-
witnessメソッド呼び出し: あるプロトコルに対応するwitness tableからメソッドを引く
// P.f()
sil hidden @$s6code031PPAAE1fyyF :
$@convention(method) <Self where Self : P> (@in_guaranteed Self) -> () { ... }
// A.f()
sil hidden @$s6code031AC1fyyF : $@convention(method) (@guaranteed A) -> () { ... }
// protocol witness for P.f() in conformance A
sil private [transparent] [thunk] @$s6code031ACAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) (@in_guaranteed A) -> () { ... }
// B.f()
sil hidden @$s6code031BC1fyyF : $@convention(method) (@guaranteed B) -> () { ... }
// protocol witness for P.f() in conformance C
sil private [transparent] [thunk] @$s6code031CCAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) <τ_0_0 where τ_0_0 : C> (@in_guaranteed τ_0_0) -> () { ... }
// D.f()
sil hidden @$s6code031DC1fyyF : $@convention(method) (@guaranteed D) -> () { ... }
sil_vtable A {
#A.f!1: (A) -> () -> () : @$s6code031AC1fyyF // A.f()
#A.init!allocator.1: (A.Type) -> () -> A : @$s6code031ACACycfC // A.__allocating_init()
#A.deinit!deallocator.1: @$s6code031ACfD // A.__deallocating_deinit
}
sil_vtable B {
#A.f!1: (A) -> () -> () : @$s6code031BC1fyyF [override] // B.f()
#A.init!allocator.1: (A.Type) -> () -> A : @$s6code031BCACycfC [override] // B.__allocating_init()
#B.deinit!deallocator.1: @$s6code031BCfD // B.__deallocating_deinit
}
sil_vtable C {
#C.init!allocator.1: (C.Type) -> () -> C : @$s6code031CCACycfC // C.__allocating_init()
#C.deinit!deallocator.1: @$s6code031CCfD // C.__deallocating_deinit
}
sil_vtable D {
#C.init!allocator.1: (C.Type) -> () -> C : @$s6code031DCACycfC [override] // D.__allocating_init()
#D.f!1: (D) -> () -> () : @$s6code031DC1fyyF // D.f()
#D.deinit!deallocator.1: @$s6code031DCfD // D.__deallocating_deinit
}
sil_witness_table hidden A: P module code03 {
method #P.f!1: <Self where Self : P> (Self) -> () -> () :
@$s6code031ACAA1PA2aDP1fyyFTW // protocol witness for P.f() in conformance A
}
sil_witness_table hidden C: P module code03 {
method #P.f!1: <Self where Self : P> (Self) -> () -> () :
@$s6code031CCAA1PA2aDP1fyyFTW // protocol witness for P.f() in conformance C
}
// main()
sil hidden @$s6code034mainyyF : $@convention(thin) () -> () {
bb0:
%0 = metatype $@thick A.Type // user: %2
// function_ref A.__allocating_init()
%1 = function_ref @$s6code031ACACycfC : $@convention(method) (@thick A.Type) -> @owned A // user: %2
%2 = apply %1(%0) : $@convention(method) (@thick A.Type) -> @owned A // users: %5, %4, %3
%3 = class_method %2 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %4
%4 = apply %3(%2) : $@convention(method) (@guaranteed A) -> ()
strong_release %2 : $A // id: %5
%6 = metatype $@thick B.Type // user: %8
// function_ref B.__allocating_init()
%7 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %8
%8 = apply %7(%6) : $@convention(method) (@thick B.Type) -> @owned B // users: %11, %10, %9
%9 = class_method %8 : $B, #B.f!1 : (B) -> () -> (), $@convention(method) (@guaranteed B) -> () // user: %10
%10 = apply %9(%8) : $@convention(method) (@guaranteed B) -> ()
strong_release %8 : $B // id: %11
%12 = metatype $@thick B.Type // user: %14
// function_ref B.__allocating_init()
%13 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %14
%14 = apply %13(%12) : $@convention(method) (@thick B.Type) -> @owned B // user: %15
%15 = upcast %14 : $B to $A // users: %18, %17, %16
%16 = class_method %15 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %17
%17 = apply %16(%15) : $@convention(method) (@guaranteed A) -> ()
strong_release %15 : $A // id: %18
%19 = metatype $@thick C.Type // user: %21
// function_ref C.__allocating_init()
%20 = function_ref @$s6code031CCACycfC : $@convention(method) (@thick C.Type) -> @owned C // user: %21
%21 = apply %20(%19) : $@convention(method) (@thick C.Type) -> @owned C // user: %23
%22 = alloc_stack $C // users: %23, %27, %26, %25
store %21 to %22 : $*C // id: %23
// function_ref P.f()
%24 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %25
%25 = apply %24<C>(%22) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %22 : $*C // id: %26
dealloc_stack %22 : $*C // id: %27
%28 = metatype $@thick D.Type // user: %30
// function_ref D.__allocating_init()
%29 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %30
%30 = apply %29(%28) : $@convention(method) (@thick D.Type) -> @owned D // users: %33, %32, %31
%31 = class_method %30 : $D, #D.f!1 : (D) -> () -> (), $@convention(method) (@guaranteed D) -> () // user: %32
%32 = apply %31(%30) : $@convention(method) (@guaranteed D) -> ()
strong_release %30 : $D // id: %33
%34 = metatype $@thick D.Type // user: %36
// function_ref D.__allocating_init()
%35 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %36
%36 = apply %35(%34) : $@convention(method) (@thick D.Type) -> @owned D // user: %37
%37 = upcast %36 : $D to $C // user: %39
%38 = alloc_stack $C // users: %39, %43, %42, %41
store %37 to %38 : $*C // id: %39
// function_ref P.f()
%40 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %41
%41 = apply %40<(C)>(%38) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %38 : $*C // id: %42
dealloc_stack %38 : $*C // id: %43
%44 = tuple () // user: %45
return %44 : $() // id: %45
} // end sil function '$s6code034mainyyF'
-
P.f(): $s6code031PPAAE1fyyF
-
A.f(): $s6code031AC1fyyF
-
protocol witness for P.f() in conformance A: $s6code031ACAA1PA2aDP1fyyFTW
-
B.f(): $s6code031BC1fyyF
-
protocol witness for P.f() in conformance C: $s6code031CCAA1PA2aDP1fyyFTW
-
D.f(): $s6code031DC1fyyF
- A.fに関してはクラスメソッドと、witnessメソッドの2つが生成されている
class A: P {
func f() { print("A.f") }
}
- C.fに関してはwitnessメソッドだけが生成されていて、クラスメソッドはない
class C: P {
}
// protocol witness for P.f() in conformance A
sil private [transparent] [thunk] @$s6code031ACAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) (@in_guaranteed A) -> () {
// %0 // user: %1
bb0(%0 : $*A):
%1 = load %0 : $*A // users: %2, %3
%2 = class_method %1 : $A, #A.f!1 : (A) -> () -> (),
$@convention(method) (@guaranteed A) -> () // user: %3
%3 = apply %2(%1) : $@convention(method) (@guaranteed A) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function '$s6code031ACAA1PA2aDP1fyyFTW'
[.code-highlight: 7-9]
// protocol witness for P.f() in conformance A
sil private [transparent] [thunk] @$s6code031ACAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) (@in_guaranteed A) -> () {
// %0 // user: %1
bb0(%0 : $*A):
%1 = load %0 : $*A // users: %2, %3
%2 = class_method %1 : $A, #A.f!1 : (A) -> () -> (),
$@convention(method) (@guaranteed A) -> () // user: %3
%3 = apply %2(%1) : $@convention(method) (@guaranteed A) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function '$s6code031ACAA1PA2aDP1fyyFTW'
class_method
命令でvtableから関数を取り出し、呼び出す。
// protocol witness for P.f() in conformance C
sil private [transparent] [thunk] @$s6code031CCAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) <τ_0_0 where τ_0_0 : C> (@in_guaranteed τ_0_0) -> () {
// %0 // user: %2
bb0(%0 : $*τ_0_0):
// function_ref P.f()
%1 = function_ref @$s6code031PPAAE1fyyF :
$@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %2
%2 = apply %1<τ_0_0>(%0) :
$@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
%3 = tuple () // user: %4
return %3 : $() // id: %4
} // end sil function '$s6code031CCAA1PA2aDP1fyyFTW'
[.code-highlight: 7-10]
// protocol witness for P.f() in conformance C
sil private [transparent] [thunk] @$s6code031CCAA1PA2aDP1fyyFTW :
$@convention(witness_method: P) <τ_0_0 where τ_0_0 : C> (@in_guaranteed τ_0_0) -> () {
// %0 // user: %2
bb0(%0 : $*τ_0_0):
// function_ref P.f()
%1 = function_ref @$s6code031PPAAE1fyyF :
$@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %2
%2 = apply %1<τ_0_0>(%0) :
$@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
%3 = tuple () // user: %4
return %3 : $() // id: %4
} // end sil function '$s6code031CCAA1PA2aDP1fyyFTW'
- P.fのデフォルト実装を呼び出す。vtableは参照しない。
sil_vtable A {
#A.f!1: (A) -> () -> () : @$s6code031AC1fyyF // A.f()
#A.init!allocator.1: (A.Type) -> () -> A : @$s6code031ACACycfC // A.__allocating_init()
#A.deinit!deallocator.1: @$s6code031ACfD // A.__deallocating_deinit
}
sil_vtable B {
#A.f!1: (A) -> () -> () : @$s6code031BC1fyyF [override] // B.f()
#A.init!allocator.1: (A.Type) -> () -> A : @$s6code031BCACycfC [override] // B.__allocating_init()
#B.deinit!deallocator.1: @$s6code031BCfD // B.__deallocating_deinit
}
- Bのテーブルの
A.f
の欄がB.f()($s6code031BC1fyyF)でオーバライドされている
sil_vtable C {
#C.init!allocator.1: (C.Type) -> () -> C : @$s6code031CCACycfC // C.__allocating_init()
#C.deinit!deallocator.1: @$s6code031CCfD // C.__deallocating_deinit
}
sil_vtable D {
#C.init!allocator.1: (C.Type) -> () -> C : @$s6code031DCACycfC [override] // D.__allocating_init()
#D.f!1: (D) -> () -> () : @$s6code031DC1fyyF // D.f()
#D.deinit!deallocator.1: @$s6code031DCfD // D.__deallocating_deinit
}
- Cのテーブルに
C.f
の欄がない。Dのテーブルで新規のD.f
として登録されている。
sil_witness_table hidden A: P module code03 {
method #P.f!1: <Self where Self : P> (Self) -> () -> () :
@$s6code031ACAA1PA2aDP1fyyFTW // protocol witness for P.f() in conformance A
}
sil_witness_table hidden C: P module code03 {
method #P.f!1: <Self where Self : P> (Self) -> () -> () :
@$s6code031CCAA1PA2aDP1fyyFTW // protocol witness for P.f() in conformance C
}
-
AとCのwitnessメソッドがそれぞれ登録されている。
-
BとDのwitness tableはない。
%0 = metatype $@thick A.Type // user: %2
// function_ref A.__allocating_init()
%1 = function_ref @$s6code031ACACycfC : $@convention(method) (@thick A.Type) -> @owned A // user: %2
%2 = apply %1(%0) : $@convention(method) (@thick A.Type) -> @owned A // users: %5, %4, %3
%3 = class_method %2 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %4
%4 = apply %3(%2) : $@convention(method) (@guaranteed A) -> ()
strong_release %2 : $A // id: %5
[.code-highlight: 5-6]
%0 = metatype $@thick A.Type // user: %2
// function_ref A.__allocating_init()
%1 = function_ref @$s6code031ACACycfC : $@convention(method) (@thick A.Type) -> @owned A // user: %2
%2 = apply %1(%0) : $@convention(method) (@thick A.Type) -> @owned A // users: %5, %4, %3
%3 = class_method %2 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %4
%4 = apply %3(%2) : $@convention(method) (@guaranteed A) -> ()
strong_release %2 : $A // id: %5
class_method
命令でA.f
のエントリを取り出して呼び出し
%6 = metatype $@thick B.Type // user: %8
// function_ref B.__allocating_init()
%7 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %8
%8 = apply %7(%6) : $@convention(method) (@thick B.Type) -> @owned B // users: %11, %10, %9
%9 = class_method %8 : $B, #B.f!1 : (B) -> () -> (), $@convention(method) (@guaranteed B) -> () // user: %10
%10 = apply %9(%8) : $@convention(method) (@guaranteed B) -> ()
strong_release %8 : $B // id: %11
[.code-highlight: 5-6]
%6 = metatype $@thick B.Type // user: %8
// function_ref B.__allocating_init()
%7 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %8
%8 = apply %7(%6) : $@convention(method) (@thick B.Type) -> @owned B // users: %11, %10, %9
%9 = class_method %8 : $B, #B.f!1 : (B) -> () -> (), $@convention(method) (@guaranteed B) -> () // user: %10
%10 = apply %9(%8) : $@convention(method) (@guaranteed B) -> ()
strong_release %8 : $B // id: %11
class_method
命令でB.f
のエントリを取り出して呼び出しA.f
ではないので特にオーバライドは無関係
%12 = metatype $@thick B.Type // user: %14
// function_ref B.__allocating_init()
%13 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %14
%14 = apply %13(%12) : $@convention(method) (@thick B.Type) -> @owned B // user: %15
%15 = upcast %14 : $B to $A // users: %18, %17, %16
%16 = class_method %15 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %17
%17 = apply %16(%15) : $@convention(method) (@guaranteed A) -> ()
strong_release %15 : $A // id: %18
[.code-highlight: 5-7]
%12 = metatype $@thick B.Type // user: %14
// function_ref B.__allocating_init()
%13 = function_ref @$s6code031BCACycfC : $@convention(method) (@thick B.Type) -> @owned B // user: %14
%14 = apply %13(%12) : $@convention(method) (@thick B.Type) -> @owned B // user: %15
%15 = upcast %14 : $B to $A // users: %18, %17, %16
%16 = class_method %15 : $A, #A.f!1 : (A) -> () -> (), $@convention(method) (@guaranteed A) -> () // user: %17
%17 = apply %16(%15) : $@convention(method) (@guaranteed A) -> ()
strong_release %15 : $A // id: %18
- Bの値をAに
upcast
命令でアップキャストした後、class_method
命令でA.f
のエントリを取り出して呼び出し - テーブルのその欄に登録されている
B.f
が呼ばれる
%19 = metatype $@thick C.Type // user: %21
// function_ref C.__allocating_init()
%20 = function_ref @$s6code031CCACycfC : $@convention(method) (@thick C.Type) -> @owned C // user: %21
%21 = apply %20(%19) : $@convention(method) (@thick C.Type) -> @owned C // user: %23
%22 = alloc_stack $C // users: %23, %27, %26, %25
store %21 to %22 : $*C // id: %23
// function_ref P.f()
%24 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %25
%25 = apply %24<C>(%22) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %22 : $*C // id: %26
dealloc_stack %22 : $*C // id: %27
[.code-highlight: 8-9]
%19 = metatype $@thick C.Type // user: %21
// function_ref C.__allocating_init()
%20 = function_ref @$s6code031CCACycfC : $@convention(method) (@thick C.Type) -> @owned C // user: %21
%21 = apply %20(%19) : $@convention(method) (@thick C.Type) -> @owned C // user: %23
%22 = alloc_stack $C // users: %23, %27, %26, %25
store %21 to %22 : $*C // id: %23
// function_ref P.f()
%24 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %25
%25 = apply %24<C>(%22) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %22 : $*C // id: %26
dealloc_stack %22 : $*C // id: %27
P.f
のデフォルト実装を直接呼び出し- witnessテーブルは参照しない
%28 = metatype $@thick D.Type // user: %30
// function_ref D.__allocating_init()
%29 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %30
%30 = apply %29(%28) : $@convention(method) (@thick D.Type) -> @owned D // users: %33, %32, %31
%31 = class_method %30 : $D, #D.f!1 : (D) -> () -> (), $@convention(method) (@guaranteed D) -> () // user: %32
%32 = apply %31(%30) : $@convention(method) (@guaranteed D) -> ()
strong_release %30 : $D // id: %33
[.code-highlight: 5-6]
%28 = metatype $@thick D.Type // user: %30
// function_ref D.__allocating_init()
%29 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %30
%30 = apply %29(%28) : $@convention(method) (@thick D.Type) -> @owned D // users: %33, %32, %31
%31 = class_method %30 : $D, #D.f!1 : (D) -> () -> (), $@convention(method) (@guaranteed D) -> () // user: %32
%32 = apply %31(%30) : $@convention(method) (@guaranteed D) -> ()
strong_release %30 : $D // id: %33
class_method
命令でD.f
を呼び出しC.f
では無いのでオーバーライドは無関係(そもそもされていない)
%34 = metatype $@thick D.Type // user: %36
// function_ref D.__allocating_init()
%35 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %36
%36 = apply %35(%34) : $@convention(method) (@thick D.Type) -> @owned D // user: %37
%37 = upcast %36 : $D to $C // user: %39
%38 = alloc_stack $C // users: %39, %43, %42, %41
store %37 to %38 : $*C // id: %39
// function_ref P.f()
%40 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %41
%41 = apply %40<(C)>(%38) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %38 : $*C // id: %42
dealloc_stack %38 : $*C // id: %43
[.code-highlight: 5, 9-10]
%34 = metatype $@thick D.Type // user: %36
// function_ref D.__allocating_init()
%35 = function_ref @$s6code031DCACycfC : $@convention(method) (@thick D.Type) -> @owned D // user: %36
%36 = apply %35(%34) : $@convention(method) (@thick D.Type) -> @owned D // user: %37
%37 = upcast %36 : $D to $C // user: %39
%38 = alloc_stack $C // users: %39, %43, %42, %41
store %37 to %38 : $*C // id: %39
// function_ref P.f()
%40 = function_ref @$s6code031PPAAE1fyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %41
%41 = apply %40<(C)>(%38) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
destroy_addr %38 : $*C // id: %42
dealloc_stack %38 : $*C // id: %43
upcast
命令でDをCにアップキャストした後、P.f
のデフォルト実装を直接呼び出し
func invokeP<X: P>(_ x: X) {
x.f()
}
// invokeP<A>(_:)
sil hidden @$s6code037invokePyyxAA1PRzlF : $@convention(thin) <X where X : P> (@in_guaranteed X) -> () {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "x", argno 1 // id: %1
%2 = witness_method $X, #P.f!1 : <Self where Self : P> (Self) -> () -> () :
$@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %3
%3 = apply %2<X>(%0) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function '$s6code037invokePyyxAA1PRzlF'
[.code-highlight: 6-8]
// invokeP<A>(_:)
sil hidden @$s6code037invokePyyxAA1PRzlF : $@convention(thin) <X where X : P> (@in_guaranteed X) -> () {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "x", argno 1 // id: %1
%2 = witness_method $X, #P.f!1 : <Self where Self : P> (Self) -> () -> () :
$@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %3
%3 = apply %2<X>(%0) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function '$s6code037invokePyyxAA1PRzlF'
witness_method
命令によるwitnessテーブルからの関数取り出しと呼び出し- テーブル参照をインスタンスからではなくメタタイプに対して行う