当前位置: 首页 > 工具软件 > canDB.swift > 使用案例 >

Swift中使用inline

艾英范
2023-12-01

Swift中使用inline

OC代码编写中我们经常会使用static inline来修饰函数替代,得到更好的性能。
那么在swift中如何使用呢?

@inline(option)

@inline(__always) func foo1() {
    /// do something...
}
@inline(never) func foo2() {
    /// do something...
}

@inline(__always) - will make sure to always inline the function. Achieve this behavior by adding @inline(__always) before the function. Use “if your function is rather small and you would prefer your app ran faster.”
@inline(never) - will make sure to never inline the function. This can be achieved by adding @inline(never) before the function. Use “if your function is quite long and you want to avoid increasing your code segment size.”

使用 @inline(__always)会确保函数总是inline

使用@inline(never)会确保函数inline

我们知道在OC中即使用inline修饰,对编译器来说也只是一个“建议”,具体编译器会自行判断。
那么在swift中如何“建议”呢?

do nothing!啥也不用做,swift会自动判断

下面是例子

func randomInt() -> Int{
    return Int(arc4random_uniform(UInt32.max))
}

func example2(){
    println(randomInt())
}

if we look at the disassembly of example2() we will see this:

                     -[_TtC12swift_weekly14ViewController example2]:
0000000100001550         push       rbp                                         ; Objective C Implementation defined at 0x100004308 (instance)
0000000100001551         mov        rbp, rsp
0000000100001554         push       r14
0000000100001556         push       rbx
0000000100001557         sub        rsp, 0x10
000000010000155b         mov        rbx, rdi
000000010000155e         mov        rax, qword [ds:imp___got__swift_isaMask]    ; imp___got__swift_isaMask
0000000100001565         mov        rax, qword [ds:rax]
0000000100001568         and        rax, qword [ds:rbx]
000000010000156b         lea        rcx, qword [ds:_OBJC_CLASS_$__TtC12swift_weekly14ViewController] ; _OBJC_CLASS_$__TtC12swift_weekly14ViewController
0000000100001572         xor        edi, edi
0000000100001574         cmp        rax, rcx
0000000100001577         cmove      rdi, rbx
000000010000157b         test       rdi, rdi
000000010000157e         je         0x100001593

0000000100001585         mov        edi, 0xffffffff                             ; argument "upper_bound" for method imp___stubs__arc4random_uniform
000000010000158a         call       imp___stubs__arc4random_uniform
000000010000158f         mov        eax, eax
0000000100001591         jmp        0x1000015ad

0000000100001593         mov        r14, qword [ds:rax+0x58]                    ; XREF=-[_TtC12swift_weekly14ViewController example2]+46
00000001000015a7         mov        rdi, rbx
00000001000015aa         call       r14

00000001000015ad         mov        qword [ss:rbp+var_18], rax                  ; XREF=-[_TtC12swift_weekly14ViewController example2]+65
00000001000015b1         mov        rsi, qword [ds:imp___got___TMdSi]           ; imp___got___TMdSi
00000001000015b8         add        rsi, 0x8
00000001000015bc         lea        rdi, qword [ss:rbp+var_18]
00000001000015c0         call       imp___stubs___TFSs7printlnU__FQ_T_
00000001000015cd         add        rsp, 0x10
00000001000015d1         pop        rbx
00000001000015d2         pop        r14
00000001000015d4         pop        rbp
00000001000015d5         ret

Do you see that the code for example2() includes a call to the internal function imp___stubs__arc4random_uniform? but that function was in the randomInt() function, you said with rage! well, swift noticed that the randomInt() function is not long enough to be a separate entity on its own and it’s only been called once in the code so it inlined it to save calling it every time it needs to use it.

now what if we prefix that function with @inline(never)?

@inline(never) func randomInt() -> Int{
    return Int(arc4random_uniform(UInt32.max))
}

let’s disassemble it:

                     -[_TtC12swift_weekly14ViewController example2]:
0000000100001580         push       rbp                                         ; Objective C Implementation defined at 0x100004308 (instance)
0000000100001581         mov        rbp, rsp
0000000100001584         push       r14
0000000100001586         push       rbx
0000000100001587         sub        rsp, 0x10
000000010000158b         mov        rbx, rdi
000000010000158e         mov        rax, qword [ds:imp___got__swift_isaMask]    ; imp___got__swift_isaMask
0000000100001595         mov        rax, qword [ds:rax]
0000000100001598         and        rax, qword [ds:rbx]
000000010000159b         lea        rcx, qword [ds:_OBJC_CLASS_$__TtC12swift_weekly14ViewController] ; _OBJC_CLASS_$__TtC12swift_weekly14ViewController
00000001000015a2         xor        edi, edi
00000001000015a4         cmp        rax, rcx
00000001000015a7         cmove      rdi, rbx
00000001000015ab         test       rdi, rdi
00000001000015ae         je         0x1000015bc

00000001000015b5         call       __TTSf4g___TFC12swift_weekly14ViewController9randomIntfS0_FT_Si
00000001000015ba         jmp        0x1000015d6

00000001000015bc         mov        r14, qword [ds:rax+0x58]                    ; XREF=-[_TtC12swift_weekly14ViewController example2]+46
00000001000015d0         mov        rdi, rbx
00000001000015d3         call       r14

00000001000015d6         mov        qword [ss:rbp+var_18], rax                  ; XREF=-[_TtC12swift_weekly14ViewController example2]+58
00000001000015da         mov        rsi, qword [ds:imp___got___TMdSi]           ; imp___got___TMdSi
00000001000015e1         add        rsi, 0x8
00000001000015e5         lea        rdi, qword [ss:rbp+var_18]
00000001000015e9         call       imp___stubs___TFSs7printlnU__FQ_T_
00000001000015f6         add        rsp, 0x10
00000001000015fa         pop        rbx
00000001000015fb         pop        r14
00000001000015fd         pop        rbp
00000001000015fe         ret

Do you see the call to the __TTSf4g___TFC12swift_weekly14ViewController9randomIntfS0_FT_Si function? that’s the randomInt() function which we disallowed inlining for. it’s working!

rules for using @inline:

  1. use @inline(never) if your function is quite long and you want to avoid increasing your code segment size (use @inline(never))
  2. use @inline(__always) if your function is rather small and you would prefer your app ran faster (note: it doesn’t make that much of a differenence really)
  3. don’t use this keyword if you don’t know what inlining of code actually means. read this first.
 类似资料: