ART和JIT的除了编译的时机区别以外,对于编译的方式有什么区别吗?

ART是提前编译,JIT是即时编译,我想问一下除了编译的时机不同,他们具体的编译过程是否是一样,比如前端编译和后端编译他们是否有区别,是否都是davik字节码变成MIR然后变成LIR然后生成机器码,编译的具体实现是否一样,另外请教如何学习ART的编译,求推荐资料,是否直接参照编译原理有关书籍
关注者
161
被浏览
3868
Android Runtime(ART)经过了几年的发展,每个发布版本的情况都不太一样,最好是指定版本来讨论。
例如说,ART从最初只有AOT编译器,到加上了解释器,到进一步加上了JIT编译模式;ART中包含的编译器也经历了多个不同实现的“斗争”。不指定版本很难说清楚。

按正式发布的大版本看,ART里的编译器经历了:
  • Android 4.4 KitKat:只有Quick编译器可用。Portable编译器的代码虽然还存在,但并不能完全正常的工作。
  • Android 5.0 Lollipop:只有Quick编译器可用。Portable编译器状况基本同上。此时还外加了新的名为Optimizing的编译器,同样尚未完全可用。
  • Android 6.0 Marshmallow:默认使用Optimizing编译器,可选退回到Quick编译器。编译器既可以当作AOT使用,也可以当作JIT使用。Portable编译器已被删除。
  • AOSP dev master:只有Optimizing编译器。Quick编译器也已被删除(2016年3月)

所以ART里有实际意义的值得讨论的编译器就只有两个:
  • Quick:由Dalvik VM的JIT编译器移植到ART的过渡阶段用的编译器;
  • Optimizing:由V8 Crankshaft / Dart VM移植到ART的编译器。整体思路/设计源自HotSpot VM的Client Compiler(C1)。

如果还有同学纠结LLVM的话,上面说的“Portable”编译器就是ART里基于LLVM的编译器(的其中一个)。它在正式发布的Android中从来都不能完全正常的工作,后来被完全删除了。
在Portable之前,ART还有过另外几个基于LLVM的编译器的尝试。它们都挂了。

言归正传,题主问的是:
他们具体的编译过程是否是一样,比如前端编译和后端编译他们是否有区别,是否都是Davik字节码变成MIR然后变成LIR然后生成机器码

大体上说ART里的编译器用作AOT与用作JIT其实做的事情都差不多。要说有啥大体方向上的不同,最大的就是用作AOT时通常会生成PIC(position-independent code),而用作JIT时则生成带有直接地址的代码(非PIC)。

ART Quick编译器的情况

Quick编译器是从Dalvik直接移植到ART上的,所以仍然与原本Dalvik的版本保持的高度的相似性,主要是在细节上有差异而已。
发展到后来,ART Quick也一样可以当作JIT编译器使用,而不像刚开始只能用作AOT。

ART Quick与Dalvik JIT最大的不同是:前者只能以方法为编译单元来编译;而后者既可以以trace,也可以以方法为编译单元,默认是以trace为编译单元。
其它其实都大同小异。编译流程还是一样经过
输入的Dex -> 平台无关MIR -> 平台相关LIR -> 机器码
的步骤。
ART Quick搞了那么多年还是没有把寄存器分配器做好。方法内联也没弄好。总之整体来说是个相当糟糕的编译器。

ART Optimizing编译器的情况

而新的名为Optimizing的编译器则跟Quick完全不一样。如前文所说,它的作者之前是在Dart VM组做编译器的,转到ART组自然还带着一样的思路,索性就把Dart VM里的编译器移植到了ART上——“思路上”移植,代码上是重新写的。
Dart VM里的编译器源自V8 Crankshaft。
而V8 Crankshaft又源自HotSpot VM Client Compiler(C1)。
这么一来技术的源头就又跟老大哥接上轨了 >_<

所以,要了解ART Optimizing编译器,可以先从HotSpot C1的论文入手:
Design of the Java HotSpotTM Client Compiler for Java 6
先看看这篇论文里都提到了一些什么技术(例如SSA形式、Global Value Numbering之类的名词),然后再找资料来学习它们吧。我还是推荐我的书单:学习编程语言与编译优化的一个书单

然后要留意的区别是:

HotSpot C1采用了两层IR,平台无关的SSA形式的HIR,以及平台相关的传统形式的LIR。前者用于优化,后者用于寄存器分配与代码生成。

而目前ART Optimizing则只采用了一层SSA形式的HIR,优化、寄存器分配以及代码生成全部都在这层IR上进行。它的HIR某种意义上说就像是HotSpot C1的HIR与LIR的融合版,设计得还挺简洁巧妙。
它的寄存器分配的算法是在SSA形式上的线性扫描(Linear Scan),论文可以参考HotSpot C1的一个实验版:
Linear Scan Register Allocation on SSA Form

ART Optimizing的HIR最初只包含平台无关的操作,但发展一段时间之后大家觉得这对平台相关优化不利,所以在某些平台上(例如ARM、ARM64、x86)上HIR还有一些平台相关的扩展操作,以便在HIR层面上也可以做一定的平台相关优化。