一.函数类型
函数本身也有自己的类型,它由形式参数类型和返回类型组成
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
//var a: (Int, Int) -> Int
var a = addTwoInts
func addTwoInts(_ a: Double, _ b: Double) -> Double {
return a + b
}
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
//如果不注明函数类型的话,因为有2个同名函数,此时编译器是没法知道是哪个函数。
var a: (Double, Double) -> Double = addTwoInts
a(10, 20)
var b = a
b(20 ,30)
通过LLDB分析函数a和函数b
(lldb) po withUnsafePointer(to: &a){print($0)}
0x00007ff7bfefecc0
0 elements
(lldb) x/8g 0x00007ff7bfefecc0
0x7ff7bfefecc0: 0x00007ff852b30120 0x000000010023eab0
0x7ff7bfefecd0: 0x00000001000f8060 0x00000001000c03a0
0x7ff7bfefece0: 0x0000000100003500 0x00000001000ac010
0x7ff7bfefecf0: 0x00007ff7bfeff2d0 0x0000000100003500
(lldb) cat address 0x00007ff852b30120
address:0x00007ff852b30120, 110c8type metadata for () <+8> , ($sytN), External: NO libswiftCore.dylib.__DATA_CONST.__const +110c8
(lldb) po withUnsafePointer(to: &b){print($0)}
0x00007ff7bfefecc0
0 elements
(lldb)
总结:函数在Swift中也是引用类型。
//将addTwoInts的metadata赋值给a
var a: (Double, Double) -> Double = addTwoInts
//将函数a的metadata赋值给b
var b = a
源码中关于函数的Metadata。Metadata.h -> TargetFunctionTypeMetadata
//继承自TargetMetadata(kind)
//当然里面也有kind
struct TargetFunctionTypeMetadata : public TargetMetadata<Runtime> {
using StoredSize = typename Runtime::StoredSize;
using Parameter = ConstTargetMetadataPointer<Runtime, swift::TargetMetadata>;
//存放的是函数类型的掩码
TargetFunctionTypeFlags<StoredSize> Flags;
/// The type metadata for the result type.
ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> ResultType;
Parameter *getParameters() { return reinterpret_cast<Parameter *>(this + 1); }
//关于参数是一个连续的内存空间
const Parameter *getParameters() const {
return reinterpret_cast<const Parameter *>(this + 1);
}
...
//参数个数
StoredSize getNumParameters() const {
return Flags.getNumParameters();
}
...
}
//Flags的掩码枚举
enum : int_type {
NumParametersMask = 0x0000FFFFU,
ConventionMask = 0x00FF0000U,
ConventionShift = 16U,
ThrowsMask = 0x01000000U,
ParamFlagsMask = 0x02000000U,
EscapingMask = 0x04000000U,
DifferentiableMask = 0x08000000U,
GlobalActorMask = 0x10000000U,
AsyncMask = 0x20000000U,
SendableMask = 0x40000000U,
// NOTE: The next bit will need to introduce a separate flags word.
};
基于源码总结TargetFunctiontypeMetadata
数据结构,并且代码验证
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
struct TargetFunctionTypeMetadata {
var kind: Int
var flags: Int
var resultType: Any.Type
var paramaters: FunctionTypeParamater<Any.Type>
//参数个数
func parameterCount() -> Int {
return flags & 0x0000FFFF
}
}
struct FunctionTypeParamater<Element> {
var parameter: Element
mutating func value(index: Int) -> UnsafePointer<Element> {
return withUnsafePointer(to: &self) {
UnsafeRawPointer($0.advanced(by: index)).assumingMemoryBound(to: Element.self)
}
}
mutating func values(count: Int) -> UnsafeBufferPointer<Element> {
return withUnsafePointer(to: &self) {
UnsafeBufferPointer(start: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self), count: count)
}
}
}
/*
注意这里需要将函数的Type转化为Metadata,而不是函数。因此需要使用到type(of:)来获取函数的类型
as Any.Type,目前知道的只有在Class时可以不转化为Any.Type.
结构体、枚举、函数都需要使用as Any.Type来转化一下,否则编译器会认为是不同大小转化报错
至于原因,暂时没有搞清楚。例如结构体没有转化前是Struct.Type,转化后是Any.Type.
*/
let funcTypeMetadata = unsafeBitCast(type(of: addTwoInts) as Any.Type, to: UnsafeMutablePointer<TargetFunctionTypeMetadata>.self)
print("参数个数为", funcTypeMetadata.pointee.parameterCount())
let parametertypes = funcTypeMetadata.pointee.paramaters.values(count: funcTypeMetadata.pointee.parameterCount())
for (index, type) in parametertypes.enumerated() {
print("第\(index)个参数类型为:\(type)")
}
print("返回值类型:\(funcTypeMetadata.pointee.resultType)")
二.什么是闭包
闭包是一个捕获了上下文的常量或变量的函数
1.官方案例认识闭包
/*
此时的外部函数makeIncrementer执行return后就释放掉了
此时的内部函数incrementer会比外部函数的生命周期长,取决于API调用者的时机
此时的runningTotal外部函数变量,外部函数已经释放了,但是内部函数想要使用到外部函数的变量,
此时就将外部函数的变量捕获进来,才能保证内部函数在使用的过程中正常使用这个变量
此时runningTotal和incrementer()就形成了一个闭包。
也就印证了,闭包的定义。捕获了上下文的常量/变量的函数
*/
func makeIncrementer() -> () -> Int {
var runningTotal = 10
func incrementer() -> Int {
runningTotal += 1
return runningTotal
}
return incrementer
}
2.闭包表达式
{ (param) -> (returnType) in
//do something
}
- 作用域(也就是大括号)
- 参数和返回值
- 函数体(in)之后的代码
Swift中的闭包既可以当做变量,也可以当做参数传递
let closure: (Int) -> Int = {(age: Int) in
return age
}
也可以作为函数的参数
func test(param: () -> Int) {
print(param())
}
test {
return 10
}
3.尾随闭包
当我们把闭包表达式作为函数的最后一个参数时,如果闭包表达式很长,我们可以通过尾随闭包的书写方式来提高代码的可读性。
func test(_ a: Int, _ b: Int, _ c: Int, by: (_ item1: Int, _ item2: Int, _ item3: Int) -> Bool) -> Bool{
return by(a, b, c)
}
test(10, 20, 30, by: {(_ item1: Int, _ item2: Int, _ item3: Int) -> Bool in
return (item1 + item2 < item3)
})
test(10, 20, 30){
return ($0 + $1 < $2)
}
闭包表达式是Swift语法。使用闭包表达式能更简洁的传达消息。当然闭包表达式的好处有很多:
- 利用上下文推断参数和返回值类型
- 单表达式可以隐式返回,既省略
return
关键字 - 参数名称的简写(比如我们的 $0)
- 尾随闭包表达式
var array = [1, 2, 3]
array.sort(by: {(item1 : Int, item2: Int) -> Bool in return item1 < item2 })
array.sort(by: {(item1, item2) -> Bool in return item1 < item2 })
array.sort(by: {(item1, item2) in return item1 < item2 })
array.sort{(item1, item2) in item1 < item2 }
array.sort{ return $0 < $1 }
array.sort{ $0 < $1 }
array.sort(by: <)
三.捕获值
1.Block中捕获值
-(void)testBlock {
NSInteger i = 1;
/*
关于block捕获变量原理,是将i的值(1)捕获到了block中
block中访问i的值,其实就是捕获进来的i值。也就是捕获进来的变量i(1)
i += 1;只会修改外部定义的i变量,并不能影响捕获进来的i的值
如需更细则的探究,可去研究一下block底层原理
*/
void (^block)(void) = ^{
NSLog(@"block: %ld", i);
};
i += 1;
NSLog(@"before block: %ld", i); // 2
block(); // 1
NSLog(@"after block: %ld", i); // 2
}
如果我们想要外部的修改能够影响当前block内部捕获的值,我们只需要对当前捕获的变量添加__block
修饰符
-(void)testBlock1 {
/*
当添加上__block修饰符后,会将i捕获到当前的堆区。
此时无论是block内部还是外部,其实都是同一份内存空间的数据。因此无论哪个地方修改了数据,都会发生改变
*/
__block NSInteger i = 1;
void (^block)(void) = ^{
NSLog(@"block: %ld", i);
i += 1;
};
i += 1;
NSLog(@"before block: %ld", i); // 2
block(); // 2
NSLog(@"after block: %ld", i); // 3
}
2.闭包中的捕获值
将上面的Block案例转化为Swift代码
var i = 1
/*
执行到closure时,通过SIL可知,编译器会在全局变量的地址里面放我们当前的i,简单的来说就是closure中的i其实就是外部的全局变量i。
%0 = global_addr @$s4mainliSivp : $*Int
*/
let closure = {
print("closure:", i)
}
i += 1;
print("before closure:", i) // 2
closure() // 2
print("after closure:", i) // 2
可能有的人会说这段代码没有放在函数里,那么我们将上面的代码放入函数里
func test() {
var i = 1
/*
通过SIl分析,会将变量i捕获到堆区。逻辑与__block类似,closure内部和外部的变量i访问的是同一块内存空间
*/
let closure = {
print("closure:", i)
i += 1
}
i += 1;
print("before closure:", i) // 2
closure() // 2
print("after closure:", i) // 3
}
test()
3.闭包是否和Block一样有不同的类型(全局、堆区、栈区)
回顾Block中的不同类型(全局、堆区、栈区)
- (void)testBlock2 {
NSObject *o = [NSObject new];
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)o)); // 1
/*
全局block,block内部不使用外部变量,只使用静态变量/全局变量
堆block:使用局部变量/OC属性,赋值给强引用/copy修饰
栈block:使用局部变量/OC属性,没有赋值给强引用/copy修饰
*/
/*
strongBlock 堆block
为什么这里是3呢?
参考下方的copyBlock
1.被栈block捕获,引用计数+1
2.由栈block变为堆block,引用计数+1
*/
void(^strongBlock)(void) = ^{
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)o)); // 3
};
strongBlock();
void(^__weak weakBlock)(void) = ^{
NSLog(@"%ld", CFGetRetainCount((__bridge CFTypeRef)o)); // 4
};
weakBlock();
/*
栈block执行copy后,由栈block变为堆block。引用计数+1
*/
void(^copyBlock)(void) = [weakBlock copy];
copyBlock();
}
但是在闭包里就没有类型的概念了
var i = 10
/*
无论闭包内部的变量是全局/局部变量,此时的closure存放的是metadata,closure也是特殊的函数
*/
let closure = {
print("closure", i)
}
closure()
4.理解闭包的引用类型
func makeIncreasemer() -> () -> Int {
var runningTotal = 10
func increasmer() -> Int {
runningTotal += 1
return runningTotal
}
return increasmer
}
//makeInc理解为引用类型,操作的是同一块内存空间的runningTotal
let makeInc = makeIncreasemer()
print(makeInc()) // 11
print(makeInc()) // 12
print(makeInc()) // 13
//相当于创建了3个不同的实例对象
print(makeIncreasemer()()) // 11
print(makeIncreasemer()()) // 11
print(makeIncreasemer()()) // 11
通过SIL分析
//increasmer的SIL代码
//这里很清楚的能够看到,当捕获外部变量时,会调用project_box
%1 = project_box %0 : ${ var Int }, 0 // users: %16, %4, %2
Given a box T reference, produces the address of the value inside the box.
从@box T reference取出一个value的值
@box T reference对应的就是alloc_box
Allocates a reference-counted @box on the heap large enough to hold a value of type T, along
with a retain count and any other metadata required by the runtime.
The result of the instruction is the reference-counted @box reference that owns the box.
The project_box instruction is used to retrieve the address of the value inside the box.
分配一个足够大的堆空间来容纳T以及引用计数和运行时所需要的任何metadata。
简单来说就是分配一个堆空间(box),存放metdadata、refCount、T。
project_box也就意味着取这个box的地址。box可以理解为实例对象
总结:因此当编译器执行到runningTotal += 1
时,发现此时需要捕获runningTotal
,此时就会去堆区开辟内存空间来存放metadata、refCount、runningTotal
,因此runningTotal就会变成实例对象的一部分
5.总结闭包
- 闭包能从上下文捕获常量/变量,即使原数据的作用域不在也可以修改数据的值。例如runningTotal
- 每次修改捕获值的时候,其实是修改堆区内存空间的值
- 每次执行
makeIncreasemer()()
会分配不同的内存空间
四.闭包的本质
0.IR基本语法
我们发现从SIL中看不出来有用的信息,降级为IR
代码来探究闭包
i64
代表Int64
i32
代表Int32
i8
代表Int8或void *,根据上下文语义具体分析
数组
[<elementnumber> x <elementtype>]
//example
alloca [24 x i8], align 8 24个i8都是0
alloca [4 x i32] === array
结构体
%swift.refcounted = type {%swift.type*, i64}
//表示形式
%T = type {<type list>}
//example
{ i32, i32, i32 } ; 包含3个i32类型的结构体
{ float, i32 (i32) * } ; 成员是float类型和函数指针类型的结构体
指针
<type> *
//example
i64* //64位的整型
getelementptr
LLVM中我们获取数组和结构体成员,通过getelementptr
,语法规则如下:
<result> = getelementptr <ty>, <ty>* <ptrval>{, [inrange] <ty> <idx>}*
<result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, [inrange] <ty> <idx>}*
官方案例理解getelementptr
struct munger_struct {
int f1;
int f2;
};
void munge(struct munger_struct *P) {
P[0].f1 = P[1].f1 + P[2].f2;
}
//表示取munger_struct的地址,第一个索引表示在munger_struct上进行的偏移(munger_struct大小 * index),返回的数据类型还是munger_struct。
//返回数据的类型取决于*前面对于的类型
getelementptr inbounds %struct.munger_struct, %struct.munger_struct * %1, i64 0
//表示取出munger_struct中的f1,第二个索引表示在第一个索引确定的数据后,根据索引取内部的数据。
getelementptr inbounds %struct.munger_struct, %struct.munger_struct * %1, i64 0, i64 0
//表示取出munger_struct中的f2
getelementptr inbounds %struct.munger_struct, %struct.munger_struct * %1, i64 0, i64 1
int main(int argc, const char * argv[]) {
int array[4] = {1, 2, 3, 4};
int a = array[0];
return 0;
}
其中 int a = array[0] 这句对应的LLVM代码应该是这样的:
a = getelementptr inbounds [4 x i32], [4 x i32] * array, i32 0, i32 0
总结:
- 第一个索引不会改变返回的指针的类型,也就是说ptrval前面的*对应什么类型,返回就是什么类型
- 第一个索引的偏移量是由第一个索引的值和第一个ty执行的基本类型共同确定的
- 后面的索引是在数组/结构体内进行索引
- 每增加一个索引,就会使得该索引使用的基本类型和返回的指针类型去掉一层
1.闭包的本质是什么(IR)
我们熟悉了IR相关概念后,我们通过IR来分析Swift闭包
Swift代码
func makeIncreasemer() -> () -> Int {
var runningTotal = 10
func increasmer() -> Int {
runningTotal += 1
return runningTotal
}
return increasmer
}
let makeInc = makeIncreasemer()
makeInc()
分析IR代码
%swift.function = type { i8*, %swift.refcounted* }
%swift.refcounted = type { %swift.type*, i64 } ---> {i64, i64}
%swift.type = type { i64 }
%swift.full_boxmetadata = type { void (%swift.refcounted*)*, i8**, %swift.type, i32, i8* }
%TSi = type <{ i64 }>
// main函数
define i32 @main(i32 %0, i8** %1) #0 {
entry:
%2 = bitcast i8** %1 to i8*
// $s4main15makeIncreasemerSiycyF ---> main.makeIncreasemer() -> () -> Swift.Int
// { i8*, %swift.refcounted* } ----> {i8*, i64, i64},由%swift.refcounted分析得来
%3 = call swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncreasemerSiycyF"()
// 从寄存器%3提取数据, %4 = 第0个元素(i8*), %5 = 第1个元素%swift.refcounted({i64, i64})
%4 = extractvalue { i8*, %swift.refcounted* } %3, 0
%5 = extractvalue { i8*, %swift.refcounted* } %3, 1
// $s4main7makeIncSiycvp ---> main.makeInc : () -> Swift.Int
// 将%4赋值给makeInc结构体的第0个元素
store i8* %4, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main7makeIncSiycvp", i32 0, i32 0), align 8
// 将%5赋值给makeInc结构体的第1个元素
store %swift.refcounted* %5, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main7makeIncSiycvp", i32 0, i32 1), align 8
// 上面2步执行完成,相当于makeInc = 返回的闭包结构体。执行了赋值的操作
// 将结构体中的i8*存入寄存器%6
// 将结构体中的%swift.refcounted*存入寄存器%7
%6 = load i8*, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main7makeIncSiycvp", i32 0, i32 0), align 8
%7 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main7makeIncSiycvp", i32 0, i32 1), align 8
// 对%swift.refcounted*执行引用计数+1的操作,也就是执行了let makeInc = makeIncreasemer()
%8 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %7) #1
// 将%6强转为Int64
%9 = bitcast i8* %6 to i64 (%swift.refcounted*)*
// 执行寄存器%9函数,传入参数%7(%swift.refcounted*)。也就是执行了makeInc()。返回值为Int64,
%10 = call swiftcc i64 %9(%swift.refcounted* swiftself %7)
// 释放寄存器%7(%swift.refcounted*)的引用
call void @swift_release(%swift.refcounted* %7) #1
ret i32 0
}
- 闭包的数据结构为
{i8*, i64, i64}
- 使用变量接收一个闭包时,实际上会先执行
@swift_retain
对%swift_refcounted*
添加引用计数,侧面的证明闭包就是一个引用类型 - 执行闭包的时候其实是执行的
返回值 i8*(%swift_refcounted*)
。也就可以说明i8*
就是闭包执行的函数,而%swift_refcounted*
大概率就是HeapObject
翻译为Swift代码为
//{i8*, %swift_refcounted*}
struct ClosureData {
var ptr: UnsafeRawPointer
var object: HeapObject
}
struct HeapObject {
var metadata: UnsafeRawPointer
var refCount: Int
}
进入函数s4main15makeIncreasemerSiycyF
探究%swift_refcounted*
define hidden swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncreasemerSiycyF"() #0 {
entry:
// 开辟%TSi*(Int64位)的内存空间
%runningTotal.debug = alloca %TSi*, align 8
// 将内存空间地址强转为i8*
%0 = bitcast %TSi** %runningTotal.debug to i8*
// 执行llvm清零函数
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
// 开辟堆区内存空间,类型为%swift.refcounted*
%1 = call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata, i32 0, i32 2), i64 24, i64 7) #1
// 将%1强转为{ %swift.refcounted, [8 x i8] }结构体
%2 = bitcast %swift.refcounted* %1 to <{ %swift.refcounted, [8 x i8] }>*
// %3为[8 x i8]的数组
%3 = getelementptr inbounds <{ %swift.refcounted, [8 x i8] }>, <{ %swift.refcounted, [8 x i8] }>* %2, i32 0, i32 1
// 将数组强转为Int64
%4 = bitcast [8 x i8]* %3 to %TSi*
//将Int64存入%runningTotal.debug
store %TSi* %4, %TSi** %runningTotal.debug, align 8
// %._value = %TSi*结构体的第一条数据Int64
%._value = getelementptr inbounds %TSi, %TSi* %4, i32 0, i32 0
// 将10存入%._value,其实也就是将10存入了开辟的堆内存空间%1中
store i64 10, i64* %._value, align 8
// 添加引用计数
%5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %1) #1
// 执行realse
call void @swift_release(%swift.refcounted* %1) #1
// $s4main15makeIncreasemerSiycyF10increasmerL_SiyFTA ---> partial apply forwarder for increasmer #1 () -> Swift.Int in main.makeIncreasemer() -> () -> Swift.Int
// 第一个元素s4main15makeIncreasemerSiycyF10increasmerL_SiyFTA就是闭包函数地址
// 第二个元素将开辟的堆空间放入进去,同时10也存放在该堆空间上
%6 = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (i64 (%swift.refcounted*)* @"$s4main15makeIncreasemerSiycyF10increasmerL_SiyFTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* %1, 1
ret { i8*, %swift.refcounted* } %6
}
- 开辟了一块
堆区内存空间(%swift_refcounted*)
- 将堆空间其中的
[8 x i8]存入数据10
(也就是捕获值) - 将闭包执行的函数地址强转为
i8*
, 将i8*
和堆区(%swift_refcounted*)
组成的结构体{i8* ,%swift_refcounted*}
返回
2.还原闭包结构体
有了关于IR代码的逻辑后,此时我们可以通过Swift代码来还原闭包结构体
func makeIncreasemer() -> () -> Int {
var runningTotal = 10
func increasmer() -> Int {
runningTotal += 1
return runningTotal
}
return increasmer
}
let makeInc = makeIncreasemer()
//{i8*, %swift_refcounted*}
//闭包的数据结构:闭包的执行地址 + 捕获变量堆空间的地址
//Block的本质也是结构体
struct ClosureData<T> {
//闭包的地址
var ptr: UnsafeRawPointer
var object: UnsafePointer<Box<T>>
}
struct Box<T> {
var object: HeapObject
var value: T
}
struct HeapObject {
var metadata: UnsafeRawPointer
var refCount: Int
}
/*
为了获取函数的数据类型,来实现内存的绑定
*/
struct NoMeanStruct {
var f: () -> Int
}
let f = NoMeanStruct(f: makeIncreasemer())
let ptr = UnsafeMutablePointer<NoMeanStruct>.allocate(capacity: 1)
ptr.initialize(to: f)
defer {
ptr.deinitialize(count: 1)
}
//报警告,建议使用withMemoryRebound。当然使用unsafeBitCast按位转化也是没有问题的
//let closureDataPtr = unsafeBitCast(ptr, to: UnsafePointer<ClosureData<Box<Int>>>.self)
let closureData = ptr.withMemoryRebound(to: ClosureData<Box<Int>>.self, capacity: 1) {
$0.pointee
}
print(closureData.ptr) // 0x0000000100004dc0
print(closureData.object) // 0x0000000101d1c940
使用终端验证闭包函数地址0x0000000100004dc0
❯ nm -p /Users/zt/Library/Developer/Xcode/DerivedData/swiftTest-hlhwnleuvbzgkogcaxdncrsezayx/Build/Products/Debug/swiftTest | grep 0000000100004dc0
0000000100004dc0 t _$s9swiftTest15makeIncreasemerSiycyF10increasmerL_SiyFTA
❯ xcrun swift-demangle s9swiftTest15makeIncreasemerSiycyF10increasmerL_SiyFTA
$s9swiftTest15makeIncreasemerSiycyF10increasmerL_SiyFTA ---> partial apply forwarder for increasmer #1 () -> Swift.Int in swiftTest.makeIncreasemer() -> () -> Swift.Int
nm -p mach-O地址 | grep 内存地址
获取Mach-O中该内存地址数据
使用LLDB
验证0x0000000101d1c940
(lldb) x/8g 0x0000000101d1c940
0x101d1c940: 0x000000010000c308 0x0000000200000003
0x101d1c950: 0x000000000000000a 0x0000000101d1cfa0
0x101d1c960: 0x0000000100004dc0 0x0000000101d1c940
0x101d1c970: 0x000000004d55545a 0x000020a000000000
验证了IR
代码逻辑,完成对闭包数据结构的还原
3.回顾之前的函数(addTwoInts)
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
var add = addTwoInts
IR代码
define i32 @main(i32 %0, i8** %1) #0 {
entry:
%2 = bitcast i8** %1 to i8*
// $s4main3addyS2i_Sitcvp ---> main.add : (Swift.Int, Swift.Int) -> Swift.Int
// $s4main10addTwoIntsyS2i_SitF ---> main.addTwoInts(Swift.Int, Swift.Int) -> Swift.Int
// 将main.addTwoInts强转成i8*,然后将这个i8*存入main.add的一个元素中
store i8* bitcast (i64 (i64, i64)* @"$s4main10addTwoIntsyS2i_SitF" to i8*), i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main3addyS2i_Sitcvp", i32 0, i32 0), align 8
// 在main.add中存入null到第二个元素中,也就是%swift.refcounted*
store %swift.refcounted* null, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main3addyS2i_Sitcvp", i32 0, i32 1), align 8
// 函数本质为%swift.function*. type { i8*, %swift.refcounted* }
ret i32 0
}