编译器主要分为3类:前端编译器、JIT编译器、AOT编译器
前端编译器:把*.Java文件转变成*.class文件——Sun的Javac
JIT编译器:就是即时编译器,将class文件转变成机器码的过程——HotSpotVM的C1、C2
AOT编译器:直接把*.java文件编译成本地代码的过程——Excelsior JET
Javacde 编译过程主要分为以下3种
①解析与填充符号的过程
1.词法、语法分析
词法分析是将源代码的字符流转变为标记集合(单个字符是程序编写过程的最小元素、而标记则是编译过程的最小元素,关键字、变量名、字面量都可以成为标记)
如int a=b+2;包含了6个标记
语法分析是根据标记序列构造抽象语法树的过程(语法树的每一个节点都代表着程序序列中的一个语法结构,如包、类型、修饰符)
2.填充符号表
符号表是由一组符号地址和符号信息构成的表格,可以将符号表想象成哈希表中K-V值对的形式(实际上不一定是哈希表的信息,可以是有序符号表、树状符号表、栈结构符号表等)
在语义分析中,符号表所登记的内容将用于语义检查和产生中间代码
在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据
②插入式注解处理器的注解处理过程
在JDK1.6中,提供了一组插入式注解处理器的标准API在编期间对注解进行处理,可以将它看作是编译器的插件,这些插件可以读取、修改、添加抽象语法树中的任意元素。当这些插件在注解处理期间对语法树进行修改,编译器将回到解析及填充符号表的过程重新处理,直到所有的插入式注解处理器都没有再对语法树进行修改为止。
③分析与字节码生成过程
语义分析的主要任务:对结构上正确的源程序进行上下文有关性质的审查,如进行类型审查。
1.标注检查
标注检查:检查的内容包括变量使用前是否已被声明、变量与赋值之间的数据类型是否匹配等,其中一个重要的动作称为常量折叠,如int a=1+1,折叠之后就变为int a=2.
2.数据及控制流分析
数据及控制流分析是对程序上下文逻辑更进一步的验证,他可以检验出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受检查异常都被正确处理了等问题。编译期间的数据及控制流分析与类加载时的数据及控制流分析的目的基本一致,但校验范围有所区别,有一些校验项只有在编译期或运行期才能运行。如将局部变量声明为final,对运行期是没有影响的,变量的不变性仅仅由编译器在编译期间保证。
3.解语法糖
Java中最常用的语法糖主要是:泛型、变长参数、自动装箱和拆箱等,在编译阶段还原回简单的基础语法结构,该过程称为解语法糖
4.字节码生成
字节码生成阶段不仅仅把前面各个步骤所生成的信息(语法树、符合表)转化成字节码写到磁盘中去,编译器还添加了少量的代码和转换工作。如实例构造器<init>()方法和<clinit>()方法,就是在该过程添加到语法树之中。完成语法树的遍历和调整后,就会把填充了所有的符号交给ClassWrite类,生成字节码。