⚠️本文为稀土技能社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!

前言

众所周知,Kotlin团队正在开发新版Kotlin编译器,并命名为K2。那么K2又是什么意思呢?莫非是Kotlin第二版编译器的意思?

其实K2指的是乔戈里峰,海拔8611米,仅次于珠穆朗玛峰,为世界第二顶峰。登山者一般称乔戈里峰为K2,它尽管海拔排名第二,但因方位偏远及山势陡峭,乔戈里峰一般被认为是最难攀登的8000米以上顶峰之一。Kotlin团队经过K2这个姓名表明编译器重构作业的难度。

好了,没用的冷知识又增加了,在了解了世界第二顶峰是哪座之后,咱们一起来看下K2编译器是什么?与老版别编译器有什么差异?

本文首要是学习《K2编译器之路》视频的输出,感兴趣的同学能够直接检查视频,链接在文末

Kotlin编译器总体介绍

K2 编译器是什么?世界第二高峰又是哪座?

如上图所示,咱们能够认为编译器是一个黑箱,它的输入便是源代码,输出则是机器码或许方针代码。

源代码是人类编写的,一般运用高档言语编写,比方java或许kotlin,关于人类来说,易于阅读,了解和修正

机器码则是一系列供机器履行的指令,一般是主动生成的,关于人类来说难以了解,可是关于机器来说却易于了解

当然机器码也是能够手写的,远古时代的程序员便是这样作业的。可是就算是远古程序员,运用机器码开发也不是那么简略,因而程序也难以扩展到杂乱的等级。正是因为这个原因,呈现了一系列的高档言语与编译器,显著简化了编程体会

编译器的效果便是将源代码输出为机器码或许方针代码

K2 编译器是什么?世界第二高峰又是哪座?

如上所示,Kotin编译器能够将Kotlin代码编译成jvm字节码,除此之外,Kotlin编译器也能够将Kotlin代码编译成javascript或许llvm bitcode

K2 编译器是什么?世界第二高峰又是哪座?

总得来说,Kotlin编译器目前有3个方针渠道,jvmjavascriptnative,它们都有着不同的格局,因而需求将源代码编译成三种方针产品

Kotlin编译器的具体结构

前端与后端

编译器一般能够区分为前端和后端两部分,如下图所示:

K2 编译器是什么?世界第二高峰又是哪座?

当然看到前端与后端你或许会跟业务开发上的前后端产生必定的混杂,但编译器前后端是与之彻底不同的概念

  • 编译器前端:效果是构建笼统语法树和语义信息
  • 编译器后端:效果是生成机器码或许方针代码

在著名的编译原理龙书中,对编译器前端与后端做了进一步的区分

K2 编译器是什么?世界第二高峰又是哪座?

  • 编译器前端被区分为语法解析器(parser)和语义分析器
  • 编译器后端被区分为中心代码生成器和机器代码生成器,其间中心代码生成器是可选的,没有这个阶段也能够实现编译器,中心代码生成器的产品便是IR

语法解析器

K2 编译器是什么?世界第二高峰又是哪座?

语法解析器以源代码作为输入,输出笼统语法树,比方下面一段代码

K2 编译器是什么?世界第二高峰又是哪座?

这段代码对咱们来说很简略,便是个if else的判断,假如条件满足则调用meow办法,不然打印一段内容。

可是关于编译器来说,这段代码目前还仅仅一段没有语义的文本,目前对编译器毫无意义。

要让编译器知道这段代码,第一步便是给这段文本增加结构,而这些结构便是经过Kotlin言语的语法界说的。Kotlin开发者依据界说的语法编写代码,编译器依据语法解析这些文本,得到有结构的数据,这便是语法解析器的效果

比方如上图所示,if表达式要求必须以if开头,而且左右各有一个括号,假如咱们编译的代码不符合这个规范的话,编译就会报错。Kotlin的更多语法界说可检查相关网站:kotlinlang.org/docs/refere…

假如输入的源代码依据语法解析正确,语法解析器将会构建出一个笼统语法树

K2 编译器是什么?世界第二高峰又是哪座?

如上图,在解析成功后,解析器了解了代码的结构,它知道if表达式有三个部分,if表达式,then子句与else子句,并将结果存储在笼统语法树中

需求注意的是,在这一阶段,编译器还没有了解语义,解析器的方针是遵从语法了解代码结构,但在目前,它还不能分辨出节点内究竟存储了什么,它仅仅将catpet这些存储为字符串,这些字符串还没有语义,这个时分就需求语义分析器开端发挥效果了

语义分析器

K2 编译器是什么?世界第二高峰又是哪座?

下一阶段,便是语义分析器以笼统语法树为输入,并向其间的节点增加语义信息,那么问题来了,什么是语义信息?

语义信息便是代码中用到的函数,变量和类型的一切详细信息,它能回答“这个函数从哪里来?”,“这两个字符串是否引证同一变量?”,“这是什么类型?”等问题

K2 编译器是什么?世界第二高峰又是哪座?

  1. 这段代码中pet呈现了3次,都指向同一个形参,在语法树中,这些pet是没有关联互相独立的,语义信息的效果是让编译器让解这3个字符串引证的是同一个变量
  2. 语义信息同样包含类型信息,比方pet参数是Pet类型的,语义信息需求解析一切运用的类型,并找到他们引证的类或许接口,然后以相同的方式进行解析
  3. 如图调用了meow函数,语义信息的方针是了解在这种情况下该运用哪个函数,比方能够是类中的成员函数,也能够是同名的扩展函数,函数类型的特点,语义分析器需求选择出最合适的那个
  4. 语义分析器还有一个重要效果是类型揣度,有时咱们在声明特点时不需求指定类型,编译器能够揣度出特点的类型,这也是由语义分析器来完结的
  5. 当语法不正确时,语法解析器会抛出过错,当语义产生过错,比方调用了不存在的函数,或许调用函数传递的参数个数不对时,语义分析器也会抛出过错

K2 编译器是什么?世界第二高峰又是哪座?

  1. 语义分析器分析出语义信息,并将这些信息存储在一个表里,这张表是包含语法树一切节点的额外信息的一个map
  2. 比方语法树中存储的第一个pet字符串,表中存储了它是example.pets.Pet类型的函数参数,Cat字符串在表中也记录了它的类型
  3. 这也适用于第二个pet字符串,这时编译器了解了两个pet字符串其实是引证了同一个参数,而且被智能转化成了Cat类型
  4. 关于办法也是相同的,在表中存储了meowprintln办法的方位

到了这个阶段,这张表存储了各个节点的信息,每个字符串都有了语义,编译器前端的作业也就完结了。

编译器前端的方针是给源代码转化为有结构和语义的数据结构,有了这些信息,编译器后端生成方针代码也就容易多了,比方Kotlin jvm后端将语法树和语义信息作为输入,生成Jvm字节码

编译器后端

K2 编译器是什么?世界第二高峰又是哪座?

咱们知道,Kotlin能够将源代码编译成3个渠道的方针代码,因而也有着3个不同的编译器后端,为不同的方针渠道转化语法树和信息

上文提到,编译器后端包含一个可选的中心代码生成器,在Kotlin刚开端开发时,为了加快开发速度,以及在前期阶段的快速开展,没有运用任何的IR

因而老版的Jvm后端与JavaScript后端是不包含IR的,可是因为Kotlin编译器有着3个后端,明显一切后端能够同享一些代码表明的一些逻辑,简化和转化。因而Kotlin团队在开发Native后端时引进了IR

K2 编译器是什么?世界第二高峰又是哪座?

能够看到Native后端遵从了龙书的经典办法,将生成中心代码的阶段和依据IR生成方针代码的阶段分离,这一设计的目的是考虑到IR将来或许能够在不同的后端之间复用

K2编译器是什么?

K2 编译器是什么?世界第二高峰又是哪座?

如上图所示,K2编译器首要包含两个部分,新后端与新前端,其间新的Jvm后端与Js后端现已正式发布了(Native后端一开端就引进了IR),而新的编译器前端还在开发中

新的编译器后端

K2 编译器是什么?世界第二高峰又是哪座?

  1. 能够看出,新的编译器后端都运用了IR,并同享构建和操作它的逻辑
  2. 引进IR的首要目的便是在不同的后端之间同享逻辑
  3. 引进IR同时简化了支撑新的言语特性所需的作业
  4. 需求指出的是,功能改善不是新的后端的方针(功能改善首要经过一个新的前端来完结)

新的编译器前端

K2 编译器是什么?世界第二高峰又是哪座?

能够看出,新的编译器前端仍是做了相同的作业,经过语法分析与语义分析,获得语法树与语意信息,可是会得到不同的数据结构,也便是FIR(前端中心表明)

在老版前端中,最终的输出是语法树和一个包含语义信息的表,其间语法树经过PSI(程序结构接口)表明,PSI的代码最早来源于IDEA。而带有语义信息的表称作BindingContext,它是一个特殊的map,存储了PSI元素的一切语义信息

而新版前端与之不同,如下图所示:

K2 编译器是什么?世界第二高峰又是哪座?

FIR = 前端中心表明 = 带有语义信息的树

新前端运用FIR表明输出,它本质上也是一棵语法树,可是带有语义信息。树包含其节点中的一切语义信息,不再运用独自的数据来表明

所以新前端的主意其实很简略,旧前端产生两个数据结构,而新前端只产生一个数据结构

同时,新的编译器前端将给编译器和IDE都带来更好的功能,也将为Kotlin编译器插件供给揭露api

FIRIR的差异

  1. FIR即前端中心表明,坐落编译器前端,而IR即中心表明,坐落编译器后端
  2. FIR为调用解析而设计和优化,而IR则为代码生成而设计和优化,IR运用FIR构建而成
  3. 得益于FIR单一的数据结构,它的生成和更新过程能够并行履行,因而它能够带来更好的功能,FIR也会做一些脱糖的作业,将杂乱的言语结构替换为更简略的结构
  4. IR的设计方针则不包含功能上的改善,它的首要方针是在不同的后端之间同享逻辑,并降低支撑新的言语特性的成本

总结

  1. Kotlin编译器能够分为前端与后端两部分,前端担任将源代码转化成语法树与语义信息,后端担任依据这些信息生成方针代码
  2. 新的编译器后端引进了IR,一切的后端同享IR以简化生成方针代码的过程
  3. 新的编译器前端引进了FIR,将语法树与语义信息存储在一个数据结构中,同时带来必定的功能提升

目前K2编译器现已发布了alpha包,或许明年底就能够正式发布,应该也是时分了解一下K2编译器了,同时假如你需求开发Kotlin编译器插件,也有必要了解一下Kotlin编译器,希望本文对你有所帮助~

参考资料

K2 编译器之路