第10章 前端编译与优化
10.2.1 Javac的源码与调试
从Javac代码的总体结构来看,编译过程大致可以分为1个准备过程和3个处理过程,它们分别如下 所示。
1)准备过程:初始化插入式注解处理器。
2)解析与填充符号表过程,包括:
词法、语法分析。将源代码的字符流转变为标记集合,构造出抽象语法树。 ·填充符号表。产生符号地址和符号信息。
3)插入式注解处理器的注解处理过程:插入式注解处理器的执行阶段,本章的实战部分会设计一个插入式注解处理器来影响Javac的编译行为。
4)分析与字节码生成过程,包括:
标注检查。对语法的静态信息进行检查,数据流及控制流分析。对程序动态运行过程进行检查。
解语法糖。将简化代码编写的语法糖还原为原有的形式。
字节码生成。将前面各个步骤所生成的信息转化成字节码。
上述3个处理过程里,执行插入式注解时又可能会产生新的符号,如果有新的符号产生,就必须转回到之前的解析、填充符号表的过程中重新处理这些新符号,从总体来看,三者之间的关系与交互顺 序如图10-4所示。
图10-4 Javac的编译过程[2]
我们可以把上述处理过程对应到代码中,Javac编译动作的入口是 com.sun.tools.javac.main.JavaCompiler类,上述3个过程的代码逻辑集中在这个类的compile()和compile2() 方法里,其中主体代码如图10-5所示,整个编译过程主要的处理由图中标注的8个方法来完成。
图10-5 Javac编译过程的主体代码
10.2.3 注解处理器
JDK 5之后,Java语言提供了对注解(Annotations)的支持,注解在设计上原本是与普通的Java代 码一样,都只会在程序运行期间发挥作用的。但在JDK 6中又提出并通过了JSR-269提案[1],该提案设 计了一组被称为“插入式注解处理器”的标准API,可以提前至编译期对代码中的特定注解进行处理, 从而影响到前端编译器的工作过程。我们可以把插入式注解处理器看作是一组编译器的插件,当这些 插件工作时,允许读取、修改、添加抽象语法树中的任意元素。如果这些插件在处理注解期间对语法 树进行过修改,编译器将回到解析及填充符号表的过程重新处理,直到所有插入式注解处理器都没有 再对语法树进行修改为止,每一次循环过程称为一个轮次(Round),这也就对应着图10-4的那个回环 过程。 有了编译器注解处理的标准API后,程序员的代码才有可能干涉编译器的行为,由于语法树中的 任意元素,甚至包括代码注释都可以在插件中被访问到,所以通过插入式注解处理器实现的插件在功 能上有很大的发挥空间。只要有足够的创意,程序员能使用插入式注解处理器来实现许多原本只能在 编码中由人工完成的事情。譬如Java著名的编码效率工具Lombok [2],它可以通过注解来实现自动产生 getter/setter方法、进行空置检查、生成受查异常表、产生equals()和hashCode()方法,等等,帮助开发人 员消除Java的冗长代码,这些都是依赖插入式注解处理器来实现的,本章最后会设计一个如何使用插 入式注解处理器的简单实战。
本章小结
在本章中,我们从Javac编译器源码实现的层次上学习了Java源代码编译为字节码的过程,分析了 Java语言中泛型、主动装箱拆箱、条件编译等多种语法糖的前因后果,书中还有实战练习如何使用插入式注解处理器来完成一个检查程序命名规范的编译器插件。如本章概述中所说的,在前端编译器中,“优化”手段主要用于提升程序的编码效率,之所以把Javac这类将Java代码转变为字节码的编译器称作“前端编译器”,是因为它只完成了从程序到抽象语法树或中间字节码的生成,而在此之后,还有一组内置于Java虚拟机内部的“后端编译器”来完成代码优化以及从字节码生成本地机器码的过程,即前面多次提到的即时编译器或提前编译器,这个后端编译器的编译速度及编译结果质量高低,是衡量Java虚拟 机性能最重要的一个指标。在第11章中,我们将会一探后端编译器的运作和优化过程。
第11章 后端编译与优化
11.1 概述
如果我们把字节码看作是程序语言的一种中间表示形式(Intermediate Representation,IR)的话, 那编译器无论在何时、在何种状态下把Class文件转换成与本地基础设施(硬件指令集、操作系统)相关的二进制机器码,它都可以视为整个编译过程的后端。
就是编译执行和解释执行,前面jit的时候介绍过
11.3 提前编译器
就是jot提前也介绍过
11.4 编译器优化技术
经过前面对即时编译、提前编译的讲解,读者应该已经建立起一个认知:编译器的目标虽然是做 由程序代码翻译为本地机器码的工作,但其实难点并不在于能不能成功翻译出机器码,输出代码优化质量的高低才是决定编译器优秀与否的关键。在本章之前的内容里出现过许多优化措施的专业名词, 有一些是编译原理中的基础知识,譬如方法内联,只要是计算机专业毕业的读者至少都有初步的概念;但也有一些专业性比较强的名词,譬如逃逸分析,可能不少读者只听名字很难想象出来这个优化会做什么事情。本节将介绍几种HotSpot虚拟机的即时编译器在生成代码时采用的代码优化技术,以小见大,见微知著,让读者对编译器代码优化有整体理解。