class Teacher {
var age : Int = 3
var name : String = "张三"
}
var t = Teacher()
swiftc -emit-sil main.swift | xcrun swift-demangle
如果编译有问题可以添加:
swiftc -emit-sil main.swift -target x86_64-apple-ios14.0-simulator -sdk $(xcrun --show-sdk-path --sdk iphonesimulator)| xcrun swift-demangle
class Teacher {
@_hasStorage @_hasInitialValue var age: Int { get set }
@_hasStorage @_hasInitialValue var name: String { get set }
@objc deinit
init()
}
%0 %1
: 寄存器
bb0 bb1
: 代码快
$String
: SIL中的String 类型
$*String
: SIL里的 String 类型的值地址
sil_global
: 全局变量
apply
: 调用函数,并传入函数
function_ref
: 直接函数引用调用
class_method
: 通过函数表来查找实现调用
sil_vtable
: 类的函数表
thin
: 静态的
thick
: 动态的,运行时的
cond_br
: 三目运算 判断寄存器上的值进行跳转
Builtin
将 LLVM IR 的类型和方法直接暴露给 Swift 标准库,使用时没有额外的运行时负担。
@_hasStorage @_hasInitialValue var t: Teacher { get set }
// t
sil_global hidden @$s4main1tAA7TeacherCvp : $Teacher
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @$s4main1tAA7TeacherCvp // id: %2
%3 = global_addr @$s4main1tAA7TeacherCvp : $*Teacher // user: %7 :拿到全局变量的地址给%3
%4 = metatype $@thick Teacher.Type // user: %6 :获取Teacher.Type的元类型给%4
// function_ref Teacher.__allocating_init()
%5 = function_ref @$s4main7TeacherCACycfC : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %6 :初始化函数地址引用
%6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %7
store %6 to %3 : $*Teacher // id: %7
%8 = integer_literal $Builtin.Int32, 0 // user: %9
%9 = struct $Int32 (%8 : $Builtin.Int32) // user: %10
return %9 : $Int32 // id: %10
} // end sil function 'main'
- %0 -- %9 在sil中被称为寄存器(虚拟寄存器)
-
s4main1tAA7TeacherCvp : 是经过重整修改的(包含,项目名称、类名、方法名、参数名称、参数类型)可以通过 xcrun swift-demangle 还原
// Teacher.__allocating_init()
sil hidden [exact_self_class] @$s4main7TeacherCACycfC : $@convention(method) (@thick Teacher.Type) -> @owned Teacher {
// %0 "$metatype"
bb0(%0 : $@thick Teacher.Type):
%1 = alloc_ref $Teacher // user: %3
// function_ref Teacher.init()
%2 = function_ref @$s4main7TeacherCACycfc : $@convention(method) (@owned Teacher) -> @owned Teacher // user: %3
%3 = apply %2(%1) : $@convention(method) (@owned Teacher) -> @owned Teacher // user: %4
return %3 : $Teacher // id: %4
} // end sil function '$s4main7TeacherCACycfC'
让我们看一下函数调用的过程:
-
Teacher()
-
__allocating_init()
-
swift_allocObject
-
swift_slowAlloc
对Teacher进行修改
class Teacher : NSObject{
var age : Int = 3
var name : String = "张三"
}
var t = Teacher()
-
Teacher()
-
__allocating_init()
从源码中分析swift_allocObject
该函数有三个参数:
- HdapMetadata const *metadata:元数据类型;
- requiredSize:所需要的大小;
- requiredAlignmentMask:对齐所需要的掩码,可以从objc的源码中得知,其为7,因为是8字节对齐;
将requiredSize和requiredAlignmentMask传递给函数swift_slowAlloc,该函数返回了一个HeapObject类型的指针; reinterpret_cast用来做指针类型的转换;
- new (object) HeapObject(metadata):HeapObject初始化;
那么swift_slowAlloc是用来干什么的呢?
- 如果alignMask<=15则直接使用malloc 在堆上申请内存,否则内存对其后(例如:alignMask = 17,对其后 alignMask = 32)然后分配内存。
swift类的初始化流程
- 首先会调用_allocating_init():该函数有编译器生成;
- 对于纯Swift类将会再调用swift_allocObject()函数;
- 然后在swift_allocObjec()总会调用私有函数_swift_allocObject;
- 然后通过函数swift_slowAlloc调用malloc来申请堆区的内存空间;
getter/setter方法
// Teacher.age.getter
sil hidden [transparent] @$s4main7TeacherC3ageSivg : $@convention(method) (@guaranteed Teacher) -> Int {
// %0 "self" // users: %2, %1
bb0(%0 : $Teacher):
debug_value %0 : $Teacher, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Teacher, #Teacher.age // user: %3
%3 = begin_access [read] [dynamic] %2 : $*Int // users: %4, %5
%4 = load %3 : $*Int // user: %6
end_access %3 : $*Int // id: %5
return %4 : $Int // id: %6
} // end sil function '$s4main7TeacherC3ageSivg'
// Teacher.age.setter
sil hidden [transparent] @$s4main7TeacherC3ageSivs : $@convention(method) (Int, @guaranteed Teacher) -> () {
// %0 "value" // users: %6, %2
// %1 "self" // users: %4, %3
bb0(%0 : $Int, %1 : $Teacher):
debug_value %0 : $Int, let, name "value", argno 1, implicit // id: %2
debug_value %1 : $Teacher, let, name "self", argno 2, implicit // id: %3
%4 = ref_element_addr %1 : $Teacher, #Teacher.age // user: %5
%5 = begin_access [modify] [dynamic] %4 : $*Int // users: %6, %7
store %0 to %5 : $*Int // id: %6
end_access %5 : $*Int // id: %7
%8 = tuple () // user: %9
return %8 : $() // id: %9
} // end sil function '$s4main7TeacherC3ageSivs'
// Teacher.name.getter
sil hidden [transparent] @$s4main7TeacherC4nameSSvg : $@convention(method) (@guaranteed Teacher) -> @owned String {
// %0 "self" // users: %2, %1
bb0(%0 : $Teacher):
debug_value %0 : $Teacher, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Teacher, #Teacher.name // user: %3
%3 = begin_access [read] [dynamic] %2 : $*String // users: %4, %6
%4 = load %3 : $*String // users: %7, %5
retain_value %4 : $String // id: %5
end_access %3 : $*String // id: %6
return %4 : $String // id: %7
} // end sil function '$s4main7TeacherC4nameSSvg'
// Teacher.name.setter
sil hidden [transparent] @$s4main7TeacherC4nameSSvs : $@convention(method) (@owned String, @guaranteed Teacher) -> () {
// %0 "value" // users: %11, %8, %4, %2
// %1 "self" // users: %5, %3
bb0(%0 : $String, %1 : $Teacher):
debug_value %0 : $String, let, name "value", argno 1, implicit // id: %2
debug_value %1 : $Teacher, let, name "self", argno 2, implicit // id: %3
retain_value %0 : $String // id: %4
%5 = ref_element_addr %1 : $Teacher, #Teacher.name // user: %6
%6 = begin_access [modify] [dynamic] %5 : $*String // users: %8, %7, %10
%7 = load %6 : $*String // user: %9
store %0 to %6 : $*String // id: %8
release_value %7 : $String // id: %9
end_access %6 : $*String // id: %10
release_value %0 : $String // id: %11
%12 = tuple () // user: %13
return %12 : $() // id: %13
} // end sil function '$s4main7TeacherC4nameSSvs'
- 析构方法
// Teacher.deinit
sil hidden @$s4main7TeacherCfd : $@convention(method) (@guaranteed Teacher) -> @owned Builtin.NativeObject {
// %0 "self" // users: %6, %2, %1
bb0(%0 : $Teacher):
debug_value %0 : $Teacher, let, name "self", argno 1, implicit // id: %1
%2 = ref_element_addr %0 : $Teacher, #Teacher.name // user: %3
%3 = begin_access [deinit] [static] %2 : $*String // users: %5, %4
destroy_addr %3 : $*String // id: %4
end_access %3 : $*String // id: %5
%6 = unchecked_ref_cast %0 : $Teacher to $Builtin.NativeObject // user: %7
return %6 : $Builtin.NativeObject // id: %7
} // end sil function '$s4main7TeacherCfd'
// Teacher.__deallocating_deinit
sil hidden @$s4main7TeacherCfD : $@convention(method) (@owned Teacher) -> () {
// %0 "self" // users: %3, %1
bb0(%0 : $Teacher):
debug_value %0 : $Teacher, let, name "self", argno 1, implicit // id: %1
// function_ref Teacher.deinit
%2 = function_ref @$s4main7TeacherCfd : $@convention(method) (@guaranteed Teacher) -> @owned Builtin.NativeObject // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed Teacher) -> @owned Builtin.NativeObject // user: %4
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $Teacher // user: %5
dealloc_ref %4 : $Teacher // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
} // end sil function '$s4main7TeacherCfD'