JVM:文件编译过程

Posted 漫步君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM:文件编译过程相关的知识,希望对你有一定的参考价值。

Java语言的编译其实是一段不确定的操作过程

它可能是指一个前端编译器把*.java文件转变成*.class文件的过程;

也可能是指虚拟机的后端运行期编译器(JIT编译器)把字节码转变成机器码的过程;

还可能是指使用静态提前编译器(AOT编译器)直接把*.java文件编译成本地机器代码的过程。

其中这三类编译过程中有一些有代表性的编译器

>前端编译器:SunJavacEclipse JDT中的增量式编译器(ECJ

>JIT编译器:HotSpotVMC1C2编译器

>AOT编译器:GNUCompiler for the JavaGCJ)、Excelsior JET

 

Sun Javac的代码来看,编译过程大致可以分为3个过程:

>解析与填充符号表过程

>插入式注解处理器的注解处理过程

>语义分析与字节码生成过程:首先是标注检查,然后是数据及控制流分析

 

Javac编译动作的入口是com.sun.tools.javac.main.JavaCompiler类,上述三个过程的代码逻辑集中在这个类的compile()compile2()方法中,其中主体代码如下图,整个编译最关键的处理就是由图中标注的8个方法来完成

解析与符号填充

解析步骤由parseFiles方法完成,包括了词法分析和语法分析两个过程

1.1词法分析是将源代码的字符流转变为标记Token集合。关键字、变量名、字面量、运算符都可以成为标记,如“int a = b + 2”中一共有6个标记。

语法分析是根据Token序列构造抽象语法树的过程,抽象语法树是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点都代表着程序代码中的一个语法结构,例如包、类型、修饰符、运算符、接口、返回值甚至代码注释等都可以是一个语法结构。

 

注解处理器

jdk1.5之后,Java提供了对注解的支持,这些注解与普通的Java代码一样是在运行期间发挥作用的。在jdk1.6之后,提供了一组插入式注解处理器的标准API在编译期间对注解进行处理,我们可以把它看做是一组编译器的插件,在这些插件里面,可以读取、修改、添加抽象语法树中的任意元素,这样我们的代码才有可能干涉编译器的行为。

2.Javac源码中,插入式注解处理器的初始化过程是在initProcessAnnotations方法中完成的,而他的执行过程则是在processAnnotations方法中完成的。

 

语义分析和字节码生成

语法分析之后,编译器获得了程序代码的抽象语法树表示,语法书表示一个结构正确的源程序抽象,但是无法保证源程序是符合逻辑的。而语义分析是对结构上正确的源程序进行上下文有关性质的审查,如类型审查。

Javac编译过程中,语义分析过程分为标注检查和数据及控制流分析两个步骤

3.1标注检查步骤检查的内容包括注入变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等;

3.2数据及控制流分析是检查出注入程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受查异常都被正确处理等问题。

3.3Javac中,解语法糖的过程由desuguar()触发,在com.sun.tools.javac.comp.TransTypes类和com.sun.tools.javac.comp.Lower类中完成。

这里提一下语法糖(Syntactic Sugar),又称糖衣语法,指在计算机语言中添加的某种语法。这种语法对语言的功能并没影响,但是更方便程序猿使用。通常来说,使用语法糖可以增加程序的可读性,从而减少程序代码出错的机会。

Java中最常用的语法糖主要是泛型、变长参数、自动装箱/拆箱以及遍历循环(Foreach)等。虚拟机运行时不支持这些语法,它们在编译阶段还会被还原回简单的基础语法结构,这个过程称为解语法糖。

除了泛型、自动装箱、自动拆箱、遍历循环、变长参数和条件编译之外,Java语言中还有其他的语法糖:如内部类、枚举类、断言语句、对枚举和字符串(在jdk1.7中支持)的switch case支持、try语句中定义和关闭资源(jdk1.7中支持)等。

3.4生成字节码是Javac编译过程的最后一个阶段,该阶段不仅仅是吧前面各个步骤所生成的信息(语法树、符号表)转化成字节码写到磁盘中,编译器还进行了少量的代码添加和转换工作。如实例构造器<init>()方法和类构造器<clinit>()方法就是在这个阶段添加到语法树之中的。

完成的对语法树的遍历和调整之后,就会把填充了所有所需信息的符号表交给com.sun.tools.javac.jvm.ClassWriter类,由这个类的writeClass()方法输出字节码,生成最终的Class文件,到此为止整个编译过程就完全结束了。


随笔,是记忆的一种延伸


以上是关于JVM:文件编译过程的主要内容,如果未能解决你的问题,请参考以下文章

JVM - 1 - 源文件编译过程

java之JVM学习--简单理解编译和运行的过程之概览

java --代码编译和执行的整个过程

类加载的执行过程

深入理解JVM读书笔记四: (早期)编译器优化

Day336.执行引擎 -JVM