美文网首页C++别人的精品编译
Swift编译器结构分析

Swift编译器结构分析

作者: sea_biscute | 来源:发表于2018-10-04 09:07 被阅读27次

    Swift介绍

    Swift是一种高性能的语言,拥有整洁现代的语法。swift可以和C、OC的代码和框架无缝衔接,并且swift默认是内存安全的。 Swift的代码仓库包含了Swift编译器和标准库的源码,还有例如用于IDE集成的SourceKit等相关组件。

    Swift编译器

    概况来说,Swift编译器负责将Swift源码转成高效的可执行机器码。下面我们对Swift编译器的几个主要组件进行说明。

    编译器基本知识

    构建过程

    构建过程分为

    • 预处理(pre-process) 用于导入文件和展开宏.纯文本操作,不考虑语言语法含义

    • (狭义的)编译 对预处理器的输出进行编译,生成汇编语言(assemble language)。一般汇编语言代码的文件扩展名.s

    • 汇编 汇编器转为机器语言,这个过程称为汇编(assemble),输出为目标文件(object file),一般扩展名为.o

    • 链接 目标文件本身不能使用。将目标文件转换为最终可以使用的形式的过程,称为链接(link)。可执行文件默认名为a.out

    Swift编译器结构

    我们下面分析的Swift编译器,负责的流程是上面构建过程中的第二步:(狭义的)编译

    Swift的编译器主要组件包含以下几部分:

    Parsing:语法分析

    Swift的语法分析器是一个简单的,对整体通过递归向下的方式进行语法分析的手工编码词法分析器,他是在lib/Parse内实现的。该分析器负责生成不包含语义和类型信息的抽象语法树,简称AST(Abstract Syntax Tree)。这个阶段生成的AST也不包含警告和错误的注入。

    lib/Parse

    我们分析一下lib/Parse内的文件结构

    文件管理:CMakeLists.txt 内部包含一个CMakeLists.txt文件和多个以cpp为后缀名的C++文件。 CMakeLists.txt是CMake的管理文件,想了解CMake可以在文末查看。CMakeLists.txt内容为

    add_swift_library(swiftParse STATIC
     xxx.cpp
     ...
     LINK_LIBRARIES
     swiftAST
     swiftSyntax
    )
    

    源码分析文件:ParseXXX.cpp 内部的cpp文件是用于对代码进行语法分析的,例如Lexer.cppParseDecl.cppParseGeneric.cppParseStmt.cpp等文件,从命名我们就能知道他们的功能是对声明,表达式或者泛型等进行语法分析。 语法分析是将代码逐字分析,通过特定的正则表达式匹配,在词的层面上拆分成多个token,之后生成AST,想了解具体的知识可以查看之前整理的编译器学习系列,这里不展开细节。

    流程管理文件 除了用于对源码进行具体分析的文件外,lib/Parse内部还包含一些流程控制文件。 通过文件PersistentParserState.cppSyntaxParsingCache.cppSyntaxParsingContext.cpp的命名和描述我们可以推断他们是用于对语法分析状态进行存储,缓存以及通过编译器不同条件的指令执行或者略过某些步骤的。

    语法分析总结

    语法分析使用以上的几种文件,对Swift源码进行逐字分析,并且可以通过编译器指令控制分析的流程和细节,词法分析生成的AST是不包含语义和类型信息的,也不包含警告和错误等信息。

    Senmantic analysis:语义分析

    语义分析负责接收语法分析生成的AST,并将其转换成格式正确,进行了全面类型检查的AST,并且在源码中嵌入警告和错误等信息。这些功能是在lib/Sema内实现的。语义分析包含类型推断,确保可以从进行了类型检查的AST安全的生成代码。

    lib/Sema

    我们对lib/Sema内的结构进行一下分析:

    CMakeLists.txt

    语义分析的CMakeLists.txt内容如下

    if (SWIFT_FORCE_OPTIMIZED_TYPECHECKER)
     set(EXTRA_TYPECHECKER_FLAGS "FORCE_BUILD_OPTIMIZED")
    endif()
    ​
    add_swift_library(swiftSema STATIC
     xxx.cpp
     ...
     LINK_LIBRARIES
     swiftParse
     swiftAST
     swiftSerialization
     ${EXTRA_TYPECHECKER_FLAGS}
    )
    

    和语法分析不同的是,

    1. 对条件SWIFT_FORCE_OPTIMIZED_TYPECHECKER是否进行强制类型检查优化进行了判断,这些条件可以在终端调试时通过指令进行控制,之后我们会在调试Swift编译器内进行说明。

    2. 链接库为AST库,语法分析库和Serialization库,以及是否增加额外类型检查的标记

    语义分析文件

    lib/Sema内部有大量使用C和C++语言编写的分析类,语义分析因为要进行符合当前语言规则对应的检查,所以相比语法分析,文件量要大很多。

    我们进行粗略的归纳,可以划分为:

    1. CSxxx.cpp/.h

      约束系统的解决文件(solution to constraint system)

    2. xxxDiag.cpp/.h

      生成诊断的文件,我们在编译过程中的诊断,用于静态代码检查的诊断都是在语义分析阶段,通过这些诊断类去管理的。

    3. CodeSyncxxx.cpp/.h

      用于对表达式,声明等各种类型进行语义分析的文件。

    4. Constraintxxx.cpp/.h

      各种约束类

    5. Debugxxx.cpp/.h & Instrumenterxxx.cpp/.h

      用于支持调试的类

    6. Derivedxxx.cpp/.h

      各种协议的隐式派生实现

    7. NameBinding.cpp

      实现Swift的name binding

    8. TypeCheckxxx.cpp/.h

      对各种类型进行检查和语义分析,以及检查修正

    语义分析总结

    语义分析生成经过了类型检查的AST,嵌入警告和错误,以及进行类型推断。这一阶段将语法分析生成的不带有语义内容的AST转换成符合Swift语义规则的AST,这些推断和类型检查为后续的优化提供了基础。

    Clang importer

    这个模块用于导入Clang组件Clang modules ,并且将C和Objective-C输出的API对应到正确的Swift API。导入的AST的结果也会传递给语义分析。lib/ClangImporter内实现的。

    lib/ClangImporter

    我们分析一下lib/ClangImporter内的结构

    CMakeLists.txt

    set(SWIFT_GYB_FLAGS
     "-DCFDatabaseFile=${SWIFT_SOURCE_DIR}/lib/ClangImporter/CFDatabase.def")
    ​
    add_gyb_target(generated_sorted_cf_database
     SortedCFDatabase.def.gyb)
    ​
    add_swift_library(swiftClangImporter STATIC
     xxx.cpp
     LINK_LIBRARIES
     swiftAST
     swiftParse
    )
    ​
    # This property is only set by calls to clang_tablegen. It will not be set on
    # standalone builds, so it can always be safely passed.
    get_property(CLANG_TABLEGEN_TARGETS GLOBAL PROPERTY CLANG_TABLEGEN_TARGETS)
    add_dependencies(swiftClangImporter
     generated_sorted_cf_database
     ${CLANG_TABLEGEN_TARGETS})
    

    GYB(Generate Your Boilerplate)指模板生成,用于添加数据库模块。

    链接库为swiftASTswiftParseAST和语法分析。

    工具类

    内容还有使用C和C++语言编写的工具类,用于方便的导入Clang实体提供正式的接口。内部的类有ImportEnumInfo.cpp/.hImportName.cpp/.hImportType.cpp/.h等,通过查看这些类的内容,我们发现包含#include "swift/AST/ASTContext.h"#include "clang/AST/ASTContext.h"等内容。

    由此我们可以知道,Swift在使用Objective-C的代码时,通过lib/ClangImporter导入的不是Objective-C的源码,而是OC通过Clang编译器生成的AST.

    Swfit不能使用Objective-C的宏

    Swift是不同使用OC的宏的,原因如下:

    上面的编译器基本知识说到了,宏的展开是在编译的前一个阶段,预处理阶段进行的。在预处理阶段将宏展开之后,Clang才对代码进行编译。Swift导入的是OC代码通过Clang生成的抽象语法树,OC内的宏是未经处理的代码段,所以Swift不能使用OC的宏。

    SIL generation:SIL生成

    SIL(Swift Intermediate Language),Swift的中间语言是一个Swift特定的用于进一步分析和优化Swift代码的高级的中间语言。

    SIL的生成阶段将类型检查的AST降级为"raw"SIL。这些内容是在lib/SILGen内实现的。SIL的设计文档为docs/SIL.rst

    lib/SILGen

    分析组件结构:

    CMakeLists.txt

    add_swift_library(swiftSILGen STATIC
     xxx.cpp
     ...
     LINK_LIBRARIES
     swiftSIL
    )
    

    链接库只有swiftSIL

    生成SIL的工具类

    其他的SILGenxxx.cpp是用于生成SIL的工具类。

    SIL详细分析

    SIL是Swift定制的中间语言,针对Swift进行了大量的优化,使得Swift性能得到提升。SIL也是Swift编译器的精髓所在。这一部分内容我们在SIL详解内进行专项说明。

    SIL guaranteed transformations:确保转换

    该模块负责对影响程序准确性的数据流进行额外的诊断,例如使用未初始化的变量。转换的结果是生成"正式"(canonical)SIL。这些内容在lib/Analysislib/ARClib/LoopTransformslib/Transforms内实现。

    LLVM IR Generation:生成LLVM的中间语言

    该模块将SIL降级为LLVM IR,LLVM的中间语言,使得LLVM在此基础上可以进行进一步的优化,并且生成机器码。这些内容是在lib/IRGen内实现的。

    信息补充

    Cmake和Ninja介绍

    我们这里介绍一下CMakeNinja,对它们有个基本的认识. CMake是一个开源,跨平台的用于构建,测试和打包的软件工具.CMake使用简单的平台和编译器单独配置文件来控制软件的编译流程, 通过生成本地makefiles文件和workspace,之后用于用户选择编译环境.

    Ninja是一个小而快的构建系统.它和其他构建系统的区别主要有两点: 1.它旨在将输入文件通过高级别的构建系统来生成. 2.致力于快速构建,极致的追求速度.Ninja意在取代在执行增量构建时非常慢的Make.Make在处理类似于Google Chrome这种单次就会编译超过30,000个输入文件的大型项目时,速度缓慢会体现的更加明显.Google Chrome是Ninja的主要用户,Ninja还支持安卓编译,也支持大部分使用LLVM的项目.

    参考资料

    相关文章

      网友评论

        本文标题:Swift编译器结构分析

        本文链接:https://www.haomeiwen.com/subject/ybbjoftx.html