OC代码编写中我们经常会使用static inline
来修饰函数替代宏
,得到更好的性能。
那么在swift中如何使用呢?
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中如何“建议”呢?
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
:
@inline(never)
if your function is quite long and you want to avoid increasing your code segment size (use @inline(never)
)@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)