天天看点

ART世界探险(19) - 优化编译器的编译流程ART世界探险(19) - 优化编译器的编译流程

前面,我们对于快速编译器的知识有了一点了解,对于compilerdriver,mirgraph等都有了初步的印象。

下面,我们回头看一下优化编译器的编译过程。有了前面的基础,后面的学习过程会更顺利一些。

下面我们先看个地图,看看我们将遇到哪些新的对象:

ART世界探险(19) - 优化编译器的编译流程ART世界探险(19) - 优化编译器的编译流程

我们先来看看优化编译的入口点,compile函数:

校验成功的话,下面就调用trycompile方法来完成编译。

如果编译成功了,则直接返回。如果不成功,则再调用其他方式编译。

对于arm32位的架构,我们默认使用thumb2指令集。

关于arm指令集,我们之前在《art世界探险(3) - arm 64位cpu的架构快餐教程》中有过介绍。

如果无法优化,或者要求不优化,返直接返回

指令集都不支持,那也就不用编了

如果不值得编的话,就不编了。

怎么算值不值得编呢?指令太多了的,或者是虚拟寄存器使用比较多的,就不编了,我们来看ispathologicalcase的代码:

uint16_max是两个字节的最大整数,为65535,除以4大约是16384。

下面处理空间选项,大于128单元的代码项不编译,以节省空间。

下面我们的老朋友dexcomplicationunit又出来了。

ART世界探险(19) - 优化编译器的编译流程ART世界探险(19) - 优化编译器的编译流程

然后我们构造一个hgraph对象,作用相当于quick compiler中的mirgraph.

下面构造一个hgraphbuilder对象,然后调用hgraphbuilder的buildgraph方法构造这个图。

下一步,尝试对hgraph构造ssa。

下面是不优化的情况:

下面我们再看看优化编译的部分:

下面开始调用runoptimizations进行优化,一共15轮优化。

allocateregisters是第16轮优化,liveness优化。

下面是生成目标代码:

最后分配空间,将编译的方法保存起来:

优化的过程:

intrinsicsrecognizer

第一次hconstantfolding

第二次instructionsimplifier

hdeadcodeelimination

hinliner

hbooleansimplifier

第二次hconstantfolding

sideeffectsanalysis

gvnoptimization

licm

boundscheckelimination

referencetypepropagation

第二次hdeadcodeelimination

第三次instructionsimplifier

进行liveness优化:

主要逻辑拆成initialize()和compileinternal()两部分

到bind的时候,已经进入跟具体架构相关的生成代码的部分了。比如针对arm64架构,就是codegeneratorarm64的bind:

bind之后,对于block之中的指令进行遍历。

下面处理慢路径下的操作:

最后调用汇编器生成指令

下面是arm64assembler的finalizeinstructions,其它芯片用的是通用的版本。

最后看下swapalloccompiledmethod,基本上就是分配空间了。

继续阅读