Why does @objc generate retain and release calls?

Viewed 62

I'm looking into how the @objc annotation in Swift affects the generated assembly code. From what I can tell, this annotation generates a trampoline function which performs two functions:

  1. Moves the self argument from x0 into x20 to conform to the Swift ABI
  2. Calls retain and release on all of the arguments (before and after the call into Swift code, respectively)

Here is the assembly code of the scene:WillConnectTo:options: trampoline from an iOS app, for example:

MyApp`@objc SceneDelegate.scene(_:willConnectTo:options:):
    0x102a850fc <+0>:   stp    x24, x23, [sp, #-0x40]!
    0x102a85100 <+4>:   stp    x22, x21, [sp, #0x10]
    0x102a85104 <+8>:   stp    x20, x19, [sp, #0x20]
    0x102a85108 <+12>:  stp    x29, x30, [sp, #0x30]
    0x102a8510c <+16>:  add    x29, sp, #0x30            ; =0x30 
    0x102a85110 <+20>:  mov    x19, x4
    0x102a85114 <+24>:  mov    x20, x3
    0x102a85118 <+28>:  mov    x21, x2
    0x102a8511c <+32>:  mov    x22, x0
    0x102a85120 <+36>:  bl     0x102a85640               ; symbol stub for: objc_retain
    0x102a85124 <+40>:  mov    x23, x0
    0x102a85128 <+44>:  mov    x0, x21
    0x102a8512c <+48>:  bl     0x102a85640               ; symbol stub for: objc_retain
    0x102a85130 <+52>:  mov    x21, x0
    0x102a85134 <+56>:  mov    x0, x20
    0x102a85138 <+60>:  bl     0x102a85640               ; symbol stub for: objc_retain
    0x102a8513c <+64>:  mov    x24, x0
    0x102a85140 <+68>:  mov    x0, x19
    0x102a85144 <+72>:  bl     0x102a85640               ; symbol stub for: objc_retain
    0x102a85148 <+76>:  mov    x19, x0
    0x102a8514c <+80>:  mov    x0, x21
    0x102a85150 <+84>:  mov    x20, x22
    0x102a85154 <+88>:  bl     0x102a853a4               ; function signature specialization <Arg[1] = Dead, Arg[2] = Dead> of MyApp(_: __C.UIScene, willConnectTo: __C.UISceneSession, options: __C.UISceneConnectionOptions) -> () at SceneDelegate.swift:17
->  0x102a85158 <+92>:  mov    x0, x21
    0x102a8515c <+96>:  bl     0x102a85634               ; symbol stub for: objc_release
    0x102a85160 <+100>: mov    x0, x24
    0x102a85164 <+104>: bl     0x102a85634               ; symbol stub for: objc_release
    0x102a85168 <+108>: mov    x0, x19
    0x102a8516c <+112>: bl     0x102a85634               ; symbol stub for: objc_release
    0x102a85170 <+116>: mov    x0, x23
    0x102a85174 <+120>: ldp    x29, x30, [sp, #0x30]
    0x102a85178 <+124>: ldp    x20, x19, [sp, #0x20]
    0x102a8517c <+128>: ldp    x22, x21, [sp, #0x10]
    0x102a85180 <+132>: ldp    x24, x23, [sp], #0x40
    0x102a85184 <+136>: b      0x102a85634               ; symbol stub for: objc_release

I understand why we need (1), but what is the purpose of (2)? In what scenario would these extra retain and release calls be necessary? Why can't we simply forward all of the arguments directly to the Swift function? I'm guessing there is a way for the Objective-C objects to be deallocated in the middle of the Swift function, but I'm having trouble thinking of an example of how this can happen.

0 Answers
Related