目录
函数汇编分析
/// 一、函数汇编分析
func functionAnalyInAssembly() {
// 0x100007570
func sum (_ v1:Int,_ v2:Int)->Int{
v1+v2//0x100006d20 0x100006d72
}
var fn = sum
print(MemoryLayout.size(ofValue: fn))//16
print(Mems.ptr(ofVal: &fn))//0x00007ffeefbff3d0
print(Mems.memStr(ofVal: &fn))//0x0000000100007770 0x00000001007062d0
var sumValue = fn(1,2)
print(MemoryLayout.size(ofValue: sumValue))//8
print("sumValue = ",sumValue)//3
print(Mems.ptr(ofVal: &sumValue))//0x00007ffeefbff3b0
print(Mems.memStr(ofVal: &sumValue))//0x0000000000000003
// 分析fn的内存分配情况
// 查看fn内存储的值 0x100004d20 位于代码段
// (lldb) p fn
// () -> () $R0 = 0x0000000100004d20 LCClientDemo-commond`sum #1 (Swift.Int, Swift.Int) -> Swift.Int in LCClientDemo_commond.functionAnaly() -> () at 6-02-闭包.swift:23
// 汇编查看计算fn变量的地址
// (lldb) register read rbp
// rbp = 0x00007ffeefbff5e0
// (lldb) p/x 0x00007ffeefbff5e0 - 0x10
// (Int) $R2 = 0x00007ffeefbff5d0
// 查看fn对用的16字节内存存储的内容 前8字节存储的是函数sum的地址 后8字节存储 0x00
// (lldb) memory read/2xg 0x00007ffeefbff5d0
// 0x7ffeefbff5d0: 0x0000000100004d20 0x0000000000000000
}
闭包汇编分析
/// 二、闭包汇编分析
func closureAnalyInAssembly() {
//1、未捕获变量时汇编分析
do{
print("-----------1--------------")
typealias Fn = (Int)->Int
func getFn0()->Fn{
//var num = 0
func plus(_ i:Int)->Int{
return i
}
return plus
}
//fn0的地址 plus的地址 空
//0x7ffeefbff5c0: 0x0000000100005ae0 0x0000000000000000
let fn0 = getFn0()
print(MemoryLayout.size(ofValue: fn0))//16
print(fn0(2))//2
print("")
/**
plus的调用汇编,可以看出 plus的地址为 0x100005ae0
LCClientDemo-commond`plus #1 (_:) in getFn0 #1 () in closureAnalyInAssembly():
0x100005ae0 <+0>: pushq %rbp
0x100005ae1 <+1>: movq %rsp, %rbp
0x100005ae4 <+4>: movq $0x0, -0x8(%rbp)
0x100005aec <+12>: movq %rdi, -0x8(%rbp)
0x100005af0 <+16>: movq %rdi, %rax
0x100005af3 <+19>: popq %rbp
0x100005af4 <+20>: retq
*/
}
//2、捕获变量时汇编分析
do{
print("-----------2--------------")
typealias Fn = (Int)->Int
func getFn()->Fn{
var num = 0
func plus(_ i:Int)->Int{
num+=i
return num
}
return plus
}
//fn占用16个字节 存储了调用plus相关的地址(不是plus的地址) 和 存储num开辟的堆空间地址
let fn = getFn()
//fn变量的内存大小
print(MemoryLayout.size(ofValue: fn))//16
//fn占用16个字节 前8个字节存储的是 plus的相关地址(是相关地址不是plus的地址) 后8个字节存储的是为num分配的堆空间的地址
// fn地址 前8字节plus函数相关地址 后8字节堆空间地址
//0x7ffeefbff5c8: 0x0000000100005e60 0x0000000100633ad0
print(fn(5))
let fn2 = getFn()
// fn2地址 前8字节plus函数相关地址 后8字节堆空间地址
//0x7ffeefbff5b0: 0x0000000100005e60 0x0000000100512370
print(fn2(6))
/**
分析fn的内存分布情况:
(lldb) p/x fn
() -> () $R0 = 0x0000000100005e60
(lldb) register read rax
rax = 0x0000000100005e60 LCClientDemo-commond`partial apply forwarder for plus #1 (Swift.Int) -> Swift.Int in getFn #1 () -> (Swift.Int) -> Swift.Int in LCClientDemo_commond.closureAnalyInAssembly() -> () at <compiler-generated>
(lldb) register read rbp
rbp = 0x00007ffeefbff5e0
(lldb) p/x 0x00007ffeefbff5e0 - 0x18
(Int) $R2 = 0x00007ffeefbff5c8
(lldb) memory read/2xg 0x00007ffeefbff5c8
0x7ffeefbff5c8: 0x0000000100005e60 0x0000000100633ad0
fn的调用汇编:
-> 0x10000599e <+270>: callq *%rcx
(lldb) register read rcx
rcx = 0x0000000100005e60 LCClientDemo-commond`partial apply forwarder for plus #1 (Swift.Int) -> Swift.Int in getFn #1 () -> (Swift.Int) -> Swift.Int in LCClientDemo_commond.closureAnalyInAssembly() -> () at <compiler-generated>
call 后边一般跟一个固定值 在编译阶段 函数的地址已经确定 所以一般跟固定值
fn是变量 内存储了 函数的地址 fn调用属于间接调用 所以后边跟的不是固定值 而是从寄存器或内存中取出的一个值
查看汇编时 可以作为一个经验
//可以看出0x100005e60对应的不是plus函数的地址
LCClientDemo-commond`partial apply for plus #1 (_:) in getFn #1 () in closureAnalyInAssembly():
-> 0x100005e60 <+0>: pushq %rbp
0x100005e61 <+1>: movq %rsp, %rbp
0x100005e64 <+4>: movq %r13, %rsi
0x100005e67 <+7>: popq %rbp
0x100005e68 <+8>: jmp 0x100005bd0
//jmp 0x100005bd0才是调用plus方法
//可知 plus的函数地址是 0x100005bd0 从而可以证明 fn内前8字节存储的是plus的相关地址 而不是直接存储了plus的地址
LCClientDemo-commond`plus #1 (_:) in getFn #1 () in closureAnalyInAssembly():
-> 0x100005bd0 <+0>: pushq %rbp
0x100005bd1 <+1>: movq %rsp, %rbp
0x100005bd4 <+4>: subq $0x90, %rsp
0x100005bdb <+11>: xorl %eax, %eax
0x100005bdd <+13>: movl %eax, %ecx
0x100005bdf <+15>: xorl %eax, %eax
0x100005be1 <+17>: leaq -0x8(%rbp), %rdx
0x100005be5 <+21>: movq %rdi, -0x48(%rbp)
0x100005be9 <+25>: movq %rdx, %rdi
0x100005bec <+28>: movq %rsi, -0x50(%rbp)
0x100005bf0 <+32>: movl %eax, %esi
0x100005bf2 <+34>: movl $0x8, %edx
0x100005bf7 <+39>: movq %rdx, -0x58(%rbp)
0x100005bfb <+43>: movq %rcx, -0x60(%rbp)
0x100005bff <+47>: movl %eax, -0x64(%rbp)
*/
}
}
闭包分析 数组相关
/// 三、闭包分析 数组相关
func closureAndArray(){
var functions:[()->Int] = []
for i in 1...3 {
//相当于下面两种写法
functions.append{i}
// let closure:()->Int = {() in return i}
// functions.append(closure)
// func fn ()->Int{
// return i
// }
// functions.append(fn)
/**
闭包:
i 是局部变量
被函数或闭包{i}捕获
*/
}
for fn in functions {
/**
fn 前8个字节 函数地址相关 后8个字节堆空间地址
*/
/**
(lldb) p fn
() -> () $R0 = 0x0000000100005bd0 LCClientDemo-commond`partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed () -> (@out Swift.Int) to @escaping @callee_guaranteed () -> (@unowned Swift.Int) at <compiler-generated>
-> 0x100004fa0 <+1264>: callq *%rcx
(lldb) register read rcx
rcx = 0x0000000100005bd0 LCClientDemo-commond`partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed () -> (@out Swift.Int) to @escaping @callee_guaranteed () -> (@unowned Swift.Int) at <compiler-generated>
-> 0x100005bd0 <+0>: pushq %rbp
0x100005bd1 <+1>: movq %rsp, %rbp
0x100005bd4 <+4>: movq 0x10(%r13), %rdi
0x100005bd8 <+8>: movq 0x18(%r13), %rsi
0x100005bdc <+12>: popq %rbp
0x100005bdd <+13>: jmp 0x100005b80 ; reabstraction thunk helper from @escaping @callee_guaranteed () -> (@out Swift.Int) to @escaping @callee_guaranteed () -> (@unowned Swift.Int) at <compiler-generated>
*/
print(fn())
}
}
自动闭包
/// 四、自动闭包
func autoClosure() -> Void {
func getFirstPositive(_ v1:Int,_ v2:()->Int)->Int{
return v1 > 0 ? v1 : v2()
}
let first = getFirstPositive(10) { () -> Int in
20
}
print(first)
let first1 = getFirstPositive(-1) { () -> Int in
20
}
print(first1)
func getFirstPositive1(_ v1:Int,_ v2:@autoclosure ()->Int)->Int{
return v1 > 0 ? v1 : v2()
}
let first2 = getFirstPositive1(10, 20)
print(first2)
let first3 = getFirstPositive1(-1, 20)
print(first3)
}
测试
/// 五、测试6
func test6() -> Void {
func add(_ num:Int)->(inout Int)->Void{
func plus(v:inout Int)->Void{
v += num
}
return plus
}
var v = 5
add(20)(&v)
print(v)
}
行者常至,为者常成!