swift编译过程
如果不懂LLVM,Clang的同学可以去了解下它的知识点 一些文章中有详细介绍 OC 的编译过程 ,本文来探索一下 Swift 的编译过程。Swift 的编译过程中使用 Swiftc ,与 Clang 一样,Swiftc 是LLVM编译架构的一个前端。
swiftc常用命令:
-dump-ast 解析和类型检查源文件 & 转换成 AST
-dump-parse 解析源文件 & 转换成 AST
-emit-assembly 生成汇编文件
-emit-bc 生成 LLVM Bitcode 文件
-emit-executable 生成已链接的可执行文件
-emit-imported-modules 生成已导入的库
-emit-ir 生成 LLVM IR 文件
-emit-library 生成已连接的库
-emit-object 生成目标文件
-emit-silgen 生成 raw SIL 文件(第一个阶段)
-emit-sil 生成 canonical SIL 文件(第2个阶段)
-index-file 为源文件生成索引数据
-print-ast 解析和类型检查源文件 & 转换成更简约的格式更好的 AST
-typecheck 解析和类型检查源文件
swift 的编译流程:
与 Clang 相比, LLVM前端的流程中,在AST 和 IR之间,多了一层中间语言SIL (Swift Intermediate Language ) , 这么做的目的是希望弥补一些 Clang 编译器的缺陷,如无法执行一些高级分析,可靠的诊断和优化,而 AST 和LLVM IR 都不是合适的选择。因此,SIL应运而生,用来解决现有的缺陷。
SIL代码
由于 SIL 是 Swift 在编译过程中的中间产物, 通过 SIL 可以了解swift 底层的实现细节,帮助我们理解一些问题)
源码生成 SIL 的命令如下:
// 将m ain.swift 编译成 SIL 代码
swiftc -emit-sil main.swift
// 将 main.swift 编译成 SIL,并保存到 main.sil 文件中
swiftc -emit-sil main.swift >> main.sil
// 将 main.swift 编译成 SIL的同时, 将命名重整后的符号恢复原样,并保存到 main.sil 文件中
swiftc -emit-sil main.swift | xcrun swift-demangle >> main.sil
SIL 语法和 IR 语法有点相似,常见语法含义:
- load: 读取数据
- sil_global:标记变量为全局变量
- hidden: 标记只针对同一个Swift模块中的对象可见
- alloc_global: 开辟全局变量的内存
- global_addr: 获取全局变量的地址
- ref_element_addr: 获取元素地址
- init_existential_addr: 指令会生成 Existential Container 结构, 包裹着实例变量和协议对应的 PWT
- destroy_addr
- bb0 / bb1 ... : basic block 数字,表示一个代码块,SIL中没有分支语句,只有入口和出口
- alloc_ref / dealloc_ref: 开辟/释放内存
- function_ref: 获取直接派发函数地址.
- class_method: 通过函数表获取方法.
- witness_method: 通过 PWT 获取对应的函数地址
- objc_method : 获取OC 方法地址
- apply:调用函数
- store A to B : 把A 的值存储到B中。
- begin_access / end_access: 开始、结束访问
-
- [modify] / [read] / [deinit] :修改型访问、读取型访问、删除型访问
- [dynamic]:动态访问
-
- [static]:静态访问
- retain_value: 引用计数 + 1
- release_value: 引用计数 - 1
- metatype 获得元类型
-
- @thick 描述元类型代表的形式,是引用 对象类型或是其子类,
- @thin 代表一个确切的值 类型,不需要存储,
- $ : 类型标识
- %: 表示寄存器,类似局部常量,赋值后不可修改。如果再需要新的寄存器,就增加寄存器编号,这样操作有利于编译器的优化;后续进行降级操作 时,才会把这些带编号的虚拟寄存器 转换成对应体系结构的真实寄存器。
- @ : SIL中所有标识符均以@符号开头
-
- @main 方法名字是 main
- @_hasStorage 标识属性是存储属性
-
- @_hasInitialValue 标识属性有初始值
- @owned 代表函数接收者负责销毁返回值
-
- @convention 这个标识用于明确指定当函数调用时参数和返回值应该如何被处理
-
-
- @convention(c) 表示使用C函数的方式进行调用
- @convention(swift) 纯Swift函数的默认调用方式
-
-
-
- @convention(method) 柯里化的函数调用方式
- @convention(witness_method) 协议方法调用,它等同于convention(method),除了在处理范型类型参数时
-
-
-
- @convention(objc_method) Objective-C方式调用
-
常见ARM64汇编指令
bl : 地址跳转
blr : 带返回的地址跳转, 跳转回指令后面跟随寄存器中保存的地址
mov: 把一个寄存器里的值,复制到另一个寄存器