Swift底层原理-闭包

2023-05-17  本文已影响0人  祀梦_

Swift底层原理-闭包

函数类型

template <typename Runtime>
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);
  }

  Parameter getParameter(unsigned index) const {
    assert(index < getNumParameters());
    return getParameters()[index];
  }

  // 省略部分方法
}
Parameter *getParameters() { return reinterpret_cast<Parameter *>(this + 1); }

闭包介绍

func makeIncrementer() -> () -> Int {
    var runningTotal = 10
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
        
    }
    return incrementer
}

闭包表达式

定义闭包表达式

在使用闭包的时候,可以用下面的方式来定义一个闭包表达式

{ (param type) -> (return type) in
    //do somethings
}
复制代码

可以看到闭包表达式是由作用域(花括号)函数类型关键字in函数体构成

闭包作为变量和参数

var closure: (Int) -> Int = { (a: Int) -> Int in
    return a + 100
}
func func3(_ someThing: @escaping (() -> Void)) {
    
}

闭包表达式的优点

闭包捕获值

闭包捕获局部变量

func makeIncrementer() -> () -> Int {
    var runningTotal = 10
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
        
    }
    return incrementer
}

let fn = makeIncrementer()
print(fn())
print(fn())
print(fn())

// 打印结果:
// 11
// 12
// 13
// makeIncrementer()
sil hidden [ossa] @$s4main15makeIncrementerSiycyF : $@convention(thin) () -> @owned @callee_guaranteed () -> Int {
bb0:
  %0 = alloc_box ${ var Int }, var, name "runningTotal" // users: %11, %8, %1
  %1 = project_box %0 : ${ var Int }, 0           // users: %9, %6
  %2 = integer_literal $Builtin.IntLiteral, 10    // user: %5
  %3 = metatype $@thin Int.Type                   // user: %5
  // function_ref Int.init(_builtinIntegerLiteral:)
  %4 = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int // user: %5
  %5 = apply %4(%2, %3) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int // user: %6
  store %5 to [trivial] %1 : $*Int                // id: %6
  // function_ref incrementer #1 () in makeIncrementer()
  %7 = function_ref @$s4main15makeIncrementerSiycyF11incrementerL_SiyF : $@convention(thin) (@guaranteed { var Int }) -> Int // user: %10
  %8 = copy_value %0 : ${ var Int }               // user: %10
  mark_function_escape %1 : $*Int                 // id: %9
  %10 = partial_apply [callee_guaranteed] %7(%8) : $@convention(thin) (@guaranteed { var Int }) -> Int // user: %12
  destroy_value %0 : ${ var Int }                 // id: %11
  return %10 : $@callee_guaranteed () -> Int      // id: %12
} // end sil function '$s4main15makeIncrementerSiycyF'
  1. %0行,通过alloc_box申请了一个堆上的地址,并将地址给了RunningTotal,将变量存储到堆上
  2. %1行,通过project_box从堆上取出变量
  3. %7行,将取出的变量交给闭包使用。

[图片上传失败...(image-e82ef2-1684422389259)]

闭包捕获全局变量

var runningTotal = 10
func makeIncrementer() -> () -> Int {
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    return incrementer
}

let fn = makeIncrementer()
print(fn())
print(fn())
print(fn())

[图片上传失败...(image-4e5a32-1684422389259)]

[图片上传失败...(image-f8dac2-1684422389259)]

闭包的本质

IR部分语法

[<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>} //这种和C语言的结构体类似
<type> *

//example
i64* //64位的整形

LLVM中我们获取数组和结构体的成员,通过 getelementptr ,语法规则如下:

<result> = getelementptr <ty>, <ty>* <ptrval>{, [inrange] <ty> <idx>}*
<result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, [inrange] <ty> <idx}
struct munger_struct{
    int f1;
    int f2;
};

// munger_struct 的地址
// i64 0 取出的是 struct.munger_struct类型的指针
getelementptr inbounds %struct.munger_struct, %struct.munger_struct %1, i64 0

// munger_struct 第一个元素
// i64 0 取出的是 struct.munger_struct类型的指针
// i32 0取出的是 struct.munger_struct结构体中的第一个元素
getelementptr inbounds %struct.munger_struct, %struct.munger_struct %1, i64 0, i32 0

// munger_struct 第二个元素
// i64 0 取出的是 struct.munger_struct类型的指针
// i32 1取出的是 struct.munger_struct结构体中的第二个元素
getelementptr inbounds %struct.munger_struct, %struct.munger_struct %1, i64 0, i32 1

分析闭包

func makeIncrementer() -> () -> Int {
    var runningTotal = 10
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    return incrementer
}

let fn = makeIncrementer()

main函数分析

define i32 @main(i32 %0, i8** %1) #0 {
entry:
  %2 = bitcast i8** %1 to i8*
  // 调用makeIncrementer函数
  %3 = call swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncrementerSiycyF"()
  %4 = extractvalue { i8*, %swift.refcounted* } %3, 0
  %5 = extractvalue { i8*, %swift.refcounted* } %3, 1
  store i8* %4, i8** getelementptr inbounds (%swift.function, %swift.function* @"$s4main2fnSiycvp", i32 0, i32 0), align 8
  store %swift.refcounted* %5, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s4main2fnSiycvp", i32 0, i32 1), align 8
  ret i32 0
}
%swift.function = type { i8*, %swift.refcounted* }
%swift.refcounted = type { %swift.type*, i64 }
%swift.type = type { i64 }

makeIncrementer函数分析

define hidden swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncrementerSiycyF"() #0 {
entry:
  %runningTotal.debug = alloca %TSi*, align 8
  %0 = bitcast %TSi** %runningTotal.debug to i8*
  call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
      
  // 调用swift_allocObject创建一个实例对象
  %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
  %2 = bitcast %swift.refcounted* %1 to <{ %swift.refcounted, [8 x i8] }>*
  
  // 获取{ %swift.refcounted, [8 x i8] }中第二个元素[8 x i8]
  %3 = getelementptr inbounds <{ %swift.refcounted, [8 x i8] }>, <{ %swift.refcounted, [8 x i8] }>* %2, i32 0, i32 1
  %4 = bitcast [8 x i8]* %3 to %TSi*
  store %TSi* %4, %TSi** %runningTotal.debug, align 8
      
  // 取出局部变量
  %._value = getelementptr inbounds %TSi, %TSi* %4, i32 0, i32 0
  store i64 10, i64* %._value, align 8
  %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %1) #1
  call void @swift_release(%swift.refcounted* %1) #1

  // 插入局部变量地址
  %6 = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (i64 (%swift.refcounted*)* @"$s4main15makeIncrementerSiycyF11incrementerL_SiyFTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* %1, 1
  ret { i8*, %swift.refcounted* } %6
}

闭包结构还原

struct ClosureData<Box> {
    /// 函数地址
    var ptr: UnsafeRawPointer
    /// 存储捕获堆空间地址的值
    var object: UnsafePointer<Box>
}

struct Box<T> {
    var heapObject: HeapObject
    // 捕获变量/常量的值
    var value: T
}

struct HeapObject {
    var matedata: UnsafeRawPointer
    var refcount: Int
}

闭包捕获引用类型

define hidden swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncrementerSiycyF"() #0 {
entry:
  %test.debug = alloca %T4main4TestC*, align 8
  %0 = bitcast %T4main4TestC** %test.debug to i8*
  call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
  %1 = call swiftcc %swift.metadata_response @"$s4main4TestCMa"(i64 0) #7
  %2 = extractvalue %swift.metadata_response %1, 0
  %3 = call swiftcc %T4main4TestC* @"$s4main4TestCACycfC"(%swift.type* swiftself %2)
  store %T4main4TestC* %3, %T4main4TestC** %test.debug, align 8
  %4 = bitcast %T4main4TestC* %3 to %swift.refcounted*
  // 对实例对象引用计数+1
  %5 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %4) #3
  
  // 将实例对象转换成 %swift.refcounted*类型,并存储到%6中
  %6 = bitcast %T4main4TestC* %3 to %swift.refcounted*
  call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T4main4TestC*)*)(%T4main4TestC* %3) #3
  %7 = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (i64 (%swift.refcounted*)* @"$s4main15makeIncrementerSiycyF11incrementerL_SiyFTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* %6, 1
  ret { i8*, %swift.refcounted* } %7
}

闭包捕获多个值

func makeIncrementer() -> () -> Int {
    var runningTotal = 10
    var runningTotal1 = 11
    func incrementer() -> Int {
        runningTotal += 1
        runningTotal1 += runningTotal
        return runningTotal1
    }
    return incrementer
}

let fn = makeIncrementer()
print(fn())
print(fn())
print(fn())

// 打印结果
// 22
// 34
// 47
define hidden swiftcc { i8*, %swift.refcounted* } @"$s4main15makeIncrementerSiycyF"() #0 {
entry:
  %runningTotal.debug = alloca %TSi*, align 8
  %0 = bitcast %TSi** %runningTotal.debug to i8*
  call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
  %runningTotal1.debug = alloca %TSi*, align 8
  %1 = bitcast %TSi** %runningTotal1.debug to i8*
  call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)

  // 第一次调用swift_allocObject
  %2 = 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) #2
  %3 = bitcast %swift.refcounted* %2 to <{ %swift.refcounted, [8 x i8] }>*
  %4 = getelementptr inbounds <{ %swift.refcounted, [8 x i8] }>, <{ %swift.refcounted, [8 x i8] }>* %3, i32 0, i32 1
  %5 = bitcast [8 x i8]* %4 to %TSi*
  store %TSi* %5, %TSi** %runningTotal.debug, align 8
  %._value = getelementptr inbounds %TSi, %TSi* %5, i32 0, i32 0
  store i64 10, i64* %._value, align 8
      
  // 第二次调用swift_allocObject
  %6 = 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) #2
  %7 = bitcast %swift.refcounted* %6 to <{ %swift.refcounted, [8 x i8] }>*
  %8 = getelementptr inbounds <{ %swift.refcounted, [8 x i8] }>, <{ %swift.refcounted, [8 x i8] }>* %7, i32 0, i32 1
  %9 = bitcast [8 x i8]* %8 to %TSi*
  store %TSi* %9, %TSi** %runningTotal1.debug, align 8
  %._value1 = getelementptr inbounds %TSi, %TSi* %9, i32 0, i32 0
  store i64 11, i64* %._value1, align 8
  %10 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %2) #2
  %11 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %6) #2
      
  // 第三次调用swift_allocObject
  %12 = call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata.4, i32 0, i32 2), i64 32, i64 7) #2
  %13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, %swift.refcounted*, %swift.refcounted* }>*
  // 将第一个变量堆空间,存储在%13中第二个元素位置
  %14 = getelementptr inbounds <{ %swift.refcounted, %swift.refcounted*, %swift.refcounted* }>, <{ %swift.refcounted, %swift.refcounted*, %swift.refcounted* }>* %13, i32 0, i32 1
  store %swift.refcounted* %2, %swift.refcounted** %14, align 8
  // 将第二个变量堆空间,存储在%13中第三个元素位置
  %15 = getelementptr inbounds <{ %swift.refcounted, %swift.refcounted*, %swift.refcounted* }>, <{ %swift.refcounted, %swift.refcounted*, %swift.refcounted* }>* %13, i32 0, i32 2
  store %swift.refcounted* %6, %swift.refcounted** %15, align 8
  call void @swift_release(%swift.refcounted* %6) #2
  call void @swift_release(%swift.refcounted* %2) #2
  %16 = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (i64 (%swift.refcounted*)* @"$s4main15makeIncrementerSiycyF11incrementerL_SiyFTA" to i8*), %swift.refcounted* undef }, %swift.refcounted* %12, 1
  ret { i8*, %swift.refcounted* } %16
}
struct ClosureData<MutiValue> {
    /// 函数地址
    var ptr: UnsafeRawPointer
    /// 存储捕获堆空间地址的值
    var object: UnsafePointer<MutiValue>
}

struct MutiValue<T1,T2> {
    var object: HeapObject
    var value: UnsafePointer<Box<T1>>
    var value1: UnsafePointer<Box<T2>>
}

struct Box<T> {
    var object: HeapObject
    var value: T
}

struct HeapObject {
    var matedata: UnsafeRawPointer
    var refcount: Int
}

多种不同类型闭包

尾随闭包

func test(closure: () -> Void) {

}

// 以下是使用尾随闭包进行函数调用
test {
    
}

// 以下是不使用尾随闭包进行函数调用
test(closure: {
    
})

逃逸闭包

自动闭包

总结

上一篇 下一篇

猜你喜欢

热点阅读