Slide 1

Slide 1 text

Θ͍Θ͍swiftc Vol 31 ARC in Swift: So, what’s new? freddi, iOS Engineer

Slide 2

Slide 2 text

Auto Reference Counting (ARC) ͱ͸

Slide 3

Slide 3 text

ARCͱ͸? ΦϒδΣΫτͷϥΠϑαΠΫϧ؅ཧ • ϦϑΝϨϯεΧ΢ϯτʹΑΔΦϒδΣΫτͷ؅ཧ • ΦϒδΣΫτ͕ࢀর → “retain͢Δ” ʢΧ΢ϯτΛ૿΍͢ʣ • “Retain Cycle” ͕͍ΘΏΔϝϞϦϦʔΫΛى͜͢ • “Reference Cycle”, “॥؀ࢀর” ͱ΋

Slide 4

Slide 4 text

ARC ͷ঺հ at WWDC21

Slide 5

Slide 5 text

https://developer.apple.com/videos/play/wwdc2021/10216/

Slide 6

Slide 6 text

https://developer.apple.com/videos/play/wwdc2021/10216/ ARCؔ࿈ͷΦϓγϣϯ૿͑ͨ from Xcode 13

Slide 7

Slide 7 text

OPTIMIZE_OBJECT_LIFETIME in Xcode Xcode 13͔Βͷ৽͍͠Φϓγϣϯ • ʮΦϒδΣΫτण໋ͷ࠷దԽʯͱ͍͏ײ͡Ͱ঺հ • ୹ॖARC࠷దԽͱ͔ݺ͹Εͯͨ • ࣮ݧతͳΦϓγϣϯ • 20ඵ͘Β͍͔͠঺հ͞Εͯͳ͍ṖͷΦϓγϣϯ

Slide 8

Slide 8 text

ARCͷ୹ॖͱ͸?

Slide 9

Slide 9 text

Swift Compiler ίϚϯυΛݟΔ • Ϗϧυ࣌ʹͲΜͳswiftcίϚϯυ͕ݺ͹Ε͔ͨ • ͭ͡͸↓ͷͱ͜Ζ͔ΒݟΕͨΓ͢Δ ΞϓϦΛϏϧυ͢Δࡍʹݺ͹ΕΔίϚϯυΛݟΔ

Slide 10

Slide 10 text

Swift Compiler ίϚϯυΛݟΔ Swiftc ͷ௥ՃΦϓγϣϯ /../swiftc ... -enforce-exclusivity\=checked -Xfrontend -enable-copy-propagation ... # Without OPTIMIZE_OBJECT_LIFETIME 
 /../swiftc ... -enforce-exclusivity\=checked ...

Slide 11

Slide 11 text

-enable-copy-propagation swift ίϯύΠϥͷίʔυ͔ΒΦϓγϣϯΛಡΈղ͘ https://github.com/apple/swift/blob/main/include/swift/Option/FrontendOptions.td#L202

Slide 12

Slide 12 text

-enable-copy-propagation swift ίϯύΠϥͷίʔυ͔ΒΦϓγϣϯΛಡΈղ͘ • Run SIL propagation to shorten object lifetime • SIL఻೻Λ૸ΒͤɺΦϒδΣΫτͷϥΠϑλΠϜΛ୹ॖ • Α͘Θ͔ΒΜ

Slide 13

Slide 13 text

࠷దԽςΫχοΫ • ίϐʔ఻೻ɺෳࣸͷ఻೻ʢ೔ຊޠ༁ʣ • a = b; c = a + d ͱ͍͏ίʔυΛ c = b + d ʹ͢Δ࠷దԽ Copy Propagation http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/note11.html

Slide 14

Slide 14 text

Θ͔Γқ͍ྫ Copy Propagation http://itdoc.hitachi.co.jp/manuals/3000/30003D0800/GD080480.HTM

Slide 15

Slide 15 text

ARCͷཁ఺ ͳͥ࠷దԽ͕ඞཁͳͷʁ • ARCʹ͸ARCͳΓʹΦʔόʔϔου͕͋Δ • ҰํɺARCͷ৔߹ɺม਺ʹΠϯελϯεΛ୅ೖͨ͠Γ ….ɺͦͷม਺͕είʔϓ Λൈ͚ͨΓ͢Δ౓ʹࢀরΧ΢ϯλͷνΣοΫॲཧ͕ೖΔͷͰɺͦͷ෼ɺΦʔ όʔϔου͕͔͔Δͱ͍͏σϝϦοτ͕͋Γ·͢ɻ https://rakusui.org/swift_arc/

Slide 16

Slide 16 text

ARCͷཁ఺ ͳͥ࠷దԽ͕ඞཁͳͷʁ • SwiftͷதؒݴޠͰ͋ΔSwift Intermediate Language Ͱ͸ ARC͕ͲͷΑ͏ʹॲཧ͞Ε͍ͯΔͷ͔͕໨ʹݟ͑ͯΘ͔Δ • தؒݴޠ͕ੜ੒͞ΕΔͱ͖ʹΧ΢ϯτͷॲཧ͕ૠೖ͞ΕΔ • ௨ৗͷSwiftͷίʔυͩͱݟ͑ͳ͍

Slide 17

Slide 17 text

Swift Intermedia Language ๻ͷొஃͩͱ਌ͷإΑΓ΋ݟΔ͜ͱʹͳΔ SILʹ͍ͭͯ • Swift͕ίϯύΠϧ͞ΕΔͱ͖ͷϑϩʔதͷதؒݴޠ • Swiftಛ༗ͷ࠷దԽ΍਍அ͕ߦΘΕΔ • Լͷਤ֮͑ͯؼ͍ͬͯͩ͘͞ AST AS T
 (Typed) SIL I R
 (LLVM) 📱 App

Slide 18

Slide 18 text

SIL Ͱͷ ARC ͷදݱʹ͍ͭͯ Reference Count ΛݮΒ͢ɾ૿΍͢ίʔυ • strong_retain • Χ΢ϯτΛʴ̍͢Δ • strong_release • Χ΢ϯτΛʔ̍͢Δ • ͋ͱΧ΢ϯτ͕0ҎԼʹͳͬͨΦϒδΣΫτΛഁغ

Slide 19

Slide 19 text

࣮ࡍͷSILͰͷARCΧ΢ϯτΛݟΔ ҎԼͷίʔυΛม׵ class Cat { func meow(){} } do { let mike = Cat() let tama = mike tama.meow() }

Slide 20

Slide 20 text

࣮ࡍͷSILͰͷARCΧ΢ϯτΛݟΔ ࣮ࡍͷίʔυʹ͍ͭͯ(Ұ෦ൈਮ) … %4 = apply %3(%2) : $@convention(method) ... debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Reference Count͕͋Δ࠷దԽࡁΈ(canonical SIL)SIL

Slide 21

Slide 21 text

copy-propagation ΛΦϯʹͯ͠ΈΔ ࠶ͼ͜ͷίʔυ class Cat { func meow(){} } do { let mike = Cat() let tama = mike tama.meow() }

Slide 22

Slide 22 text

copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ … %4 = apply %3(%2) : $@convention(method) ... debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … copy-propagation ൈ͖

Slide 23

Slide 23 text

… %4 = apply %3(%2) : $@convention(method) ... debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Retain count (mike’s object to tama) copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ copy-propagation ൈ͖

Slide 24

Slide 24 text

… %4 = apply %3(%2) : $@convention(method) ... debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Retain count (mike’s object to tama) Decrease count (mike’s object to tama) Decrease count (mike) copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ copy-propagation ൈ͖

Slide 25

Slide 25 text

… %4 = apply %3(%2) : $@convention(method) … debug_value %4 : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> () … %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 … copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹͨ͠ޙͷίʔυ copy-propagation Ϛγ

Slide 26

Slide 26 text

… %4 = apply %3(%2) : $@convention(method) … debug_value %4 : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> () … %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 … Decrease count (mike) No retain count for tama copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹͨ͠ޙͷίʔυ copy-propagation Ϛγ

Slide 27

Slide 27 text

// main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): %2 = metatype $@thick Cat.Type // user: %4 // function_ref Cat.__allocating_init() %3 = function_ref @$s4test3CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %4 %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %11, %10, %7, %9, %8, %6, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %9 %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 %12 = integer_literal $Builtin.Int32, 0 // user: %13 %13 = struct $Int32 (%12 : $Builtin.Int32) // user: %14 return %13 : $Int32 // id: %14 } // end sil function 'main' copy-propagation ͋Γ/ͳ͠ൺֱ Φϯʹ͢Δલͷίʔυ

Slide 28

Slide 28 text

// main sil @main : $@convention(c) (Int32, UnsafeMutablePointer>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>): %2 = metatype $@thick Cat.Type // user: %4 // function_ref Cat.__allocating_init() %3 = function_ref @$s5test23CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %4 %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %9, %6, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %8 %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 %10 = integer_literal $Builtin.Int32, 0 // user: %11 %11 = struct $Int32 (%10 : $Builtin.Int32) // user: %12 return %11 : $Int32 // id: %12 } // end sil function 'main' copy-propagation ͋Γ/ͳ͠ൺֱ Φϯʹͨ͠ޙͷίʔυ

Slide 29

Slide 29 text

ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸ • weak ʹΑΔࢀর (ऑࢀর) ΋ಉ͡Α͏ʹಇ͘આ class Cat { func meow(){} } do { let mike = Cat() weak var tama = mike tama?.meow() } weak/unownedͱͷൺֱʁ

Slide 30

Slide 30 text

ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸ ࣮͸ weak ͸ΊͬͪΌ௕͘ͳΔ … %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %39, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 %6 = alloc_stack $@sil_weak Optional, var, name "tama" // users: %38, %37, %9, %11 strong_retain %4 : $Cat // id: %7 %8 = enum $Optional, #Optional.some!enumelt, %4 : $Cat // users: %10, %9 store_weak %8 to [initialization] %6 : $*@sil_weak Optional // id: %9 release_value %8 : $Optional // id: %10 %11 = begin_access [read] [static] %6 : $*@sil_weak Optional // users: %28, %21, %13 %12 = alloc_stack $Optional // users: %14, %32, %27, %24, %20, %19, %17 %13 = load_weak %11 : $*@sil_weak Optional // user: %14 store %13 to %12 : $*Optional // id: %14 %15 = integer_literal $Builtin.Int1, -1 // user: %17 %16 = integer_literal $Builtin.Int1, 0 // user: %17 %17 = select_enum_addr %12 : $*Optional, case #Optional.some!enumelt: %15, default %16 : $Builtin.Int1 // user: %18 cond_br %17, bb2, bb1 // id: %18 bb1: // Preds: bb0 destroy_addr %12 : $*Optional // id: %19 dealloc_stack %12 : $*Optional // id: %20 end_access %11 : $*@sil_weak Optional // id: %21 %22 = enum $Optional<()>, #Optional.none!enumelt // user: %23 br bb3(%22 : $Optional<()>) // id: %23 … weak/unownedͱͷൺֱʁ

Slide 31

Slide 31 text

weak/unownedͱͷൺֱʁ weak ͱ Optional ʹ͍ͭͯ • Optional ͷ ? ͸ SIL ্ͩͱ nil ͡Όͳ͍͔ΛνΣοΫ͢Δ ৚݅෼ذ͕ൃੜ͢Δ • ͳͷͰͦͷ෼ͷ৚݅෼ذ͕૿͍͑ͯΔͱ͍͏͜ͱ

Slide 32

Slide 32 text

weak/unownedͱͷൺֱʁ • unowned ʹॻ͖׵͑ͯࢼͯ͠ΈΔ class Cat { func meow(){} } do { let mike = Cat() unowned let tama = mike tama.meow() } ͡Ό͋ unowned ͸Ͳ͏Α

Slide 33

Slide 33 text

unowned ͷ΄͏͕ copy-propagation ༗ΓΑΓ௕͍ ͡Ό͋ unowned ͸Ͳ͏Α … %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %20, %12, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 %6 = alloc_stack $@sil_unowned Cat, let, name "tama" // users: %11, %19, %18 strong_retain %4 : $Cat // id: %7 %8 = ref_to_unowned %4 : $Cat to $@sil_unowned Cat // users: %14, %11, %13, %10, %9 unowned_retain %8 : $@sil_unowned Cat // id: %9 unowned_retain %8 : $@sil_unowned Cat // id: %10 store %8 to %6 : $*@sil_unowned Cat // id: %11 strong_release %4 : $Cat // id: %12 %13 = strong_copy_unowned_value %8 : $@sil_unowned Cat // users: %17, %16, %15 unowned_release %8 : $@sil_unowned Cat // id: %14 %15 = class_method %13 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %16 %16 = apply %15(%13) : $@convention(method) (@guaranteed Cat) -> () strong_release %13 : $Cat // id: %17 destroy_addr %6 : $*@sil_unowned Cat // id: %18 dealloc_stack %6 : $*@sil_unowned Cat // id: %19 strong_release %4 : $Cat // id: %20 … weak/unownedͱͷൺֱʁ

Slide 34

Slide 34 text

weak/unownedͱͷൺֱʁ unowned ʹ͍ͭͯ • unowned ΋ unowned Ͱಛ༗ͷॲཧ͕͋ΔͷͰ݁ہ௕͍ • unowned_retain ͱ͔

Slide 35

Slide 35 text

LLVMIRίʔυͷൺֱ Կ΋ͳ͠ vs copy-propagation vs unowned vs weak vs μʔΫϥΠ • ҎԼͷॱ൪Ͱ୹͍ • copy-propagation • Կ΋ͳ͠ • unowned • weak

Slide 36

Slide 36 text

Conclusion

Slide 37

Slide 37 text

Points of this talk Why we need to optimize it • OPTIMIZE_OBJECT_LIFETIME from Xcode 13 • -Xfrontend -enable-copy-propagation for swiftc • copy-propagation Ͱίʔυ΍ARCͷΦʔόʔϔουݮΒͤΔ • unowned ΍ weak ΑΓ΋୹͍

Slide 38

Slide 38 text

࣍ճ༧ࠂ

Slide 39

Slide 39 text

࣍ճ͸͕࣌ؒ͋Ε͹࣮૷ΛಡΜͰ͍͘ ָ͓͠Έʹ • https://github.com/apple/swift/blob/ 6bafc8498dd727f05ba14bf573e3f3d78de93a4e/lib/ SILOptimizer/Transforms/CopyPropagation.cpp