前面,我们对于快速编译器的知识有了一点了解,对于compilerdriver,mirgraph等都有了初步的印象。
下面,我们回头看一下优化编译器的编译过程。有了前面的基础,后面的学习过程会更顺利一些。
下面我们先看个地图,看看我们将遇到哪些新的对象:
我们先来看看优化编译的入口点,compile函数:
校验成功的话,下面就调用trycompile方法来完成编译。
如果编译成功了,则直接返回。如果不成功,则再调用其他方式编译。
对于arm32位的架构,我们默认使用thumb2指令集。
关于arm指令集,我们之前在《art世界探险(3) - arm 64位cpu的架构快餐教程》中有过介绍。
如果无法优化,或者要求不优化,返直接返回
指令集都不支持,那也就不用编了
如果不值得编的话,就不编了。
怎么算值不值得编呢?指令太多了的,或者是虚拟寄存器使用比较多的,就不编了,我们来看ispathologicalcase的代码:
uint16_max是两个字节的最大整数,为65535,除以4大约是16384。
下面处理空间选项,大于128单元的代码项不编译,以节省空间。
下面我们的老朋友dexcomplicationunit又出来了。
然后我们构造一个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,基本上就是分配空间了。