Javac编译器源代码分析

Javac编译器的编译流程主要如下图:

 

 

 

各个阶段的作用:

 

词法分析:

 

主要的作用就是读入Java源代码文件,生成Token流,用到的类如下图:

 

 

 

 

 

 

Scanner调用nextToken()方法,返回一个Token。

 

Scanner它内部究竟是怎么获得Token的呢?

 

首先它会先把 Java源文件转为Char[]数组,逐个Char去判断,遇到单词分隔符(空格)、分隔语义时,分析出Java源文件中的词。再把分析出来的单词 Char[]数组传给Table.fromChars(chars)方法,Table会生成chars的hash值,也就是Table.hashs哈希表 的索引,当哈希表里不存在相应的Name时,生成新的一个Name,把它存入到哈希表Table.hashs中。再调用用 Keywords.key(name),直接由Keywords返回Token值。Keywords中存储的就是Name和Token的关系映射,它负责 将字符集合对应到Token。

 

语法分析:

 

主要把Token流组装成一棵基本的语法树。是一个递归下降且运算符优先级的语法分析器,使用com.sun.tools.javac.parser.Parser类,根据语法由Token序列生成相应的树节点,组装成抽象语法树。

 

语义分析:

 

语义分析包括:输入到符号表->  注解处理->标注(Attr)和检查(Check)->数据流分析(Flow)->数据流分析(Flow)->转换类型:(TransTypes)->  解除语法糖:(Lower)

 

输入到符号表:

 

使用com.sun.tools.javac.comp.Enter类,此过程每个编译单元的抽象语法树的顶局节点都先被放到待处理列表中并逐个处理列表中的节点

 

所有的类符号被输入到外围作用域的符号表中

 

确定类的参数(对泛型类型而言)、超类型和接口

 

如果需要添加默认构造器

 

将类中出现的符号输入到类自身的符号表中

 

分析和检查代码中的annotation

 

 注解处理:annotation processing

 

使用com.sun.tools.javac.processing.JavacProcessingEnvironment类,并且支持用户自定义的annotation

 

编译时lombook对java文件进行编译之后会再次进入Parse and Enter步骤

 

 标注(Attr)和检查(Check):

 

是语义分析的一个步骤,使用com.sun.tools.javac.comp.Attr类和com.sun.tools.javac.comp.Check类

 

主要作用有:

 

将语法树中名字、表达式等元素与变量、方法、类型等联系到一起

 

检查变量使用前是否已声明

 

推导泛型方法的类型参数

 

检查类型匹配性

 

进行常量折叠(将常量语法树合并)

 

数据流分析(Flow):

 

使用com.sun.tools.javac.comp.Flow类

 

检查所有语句都可到达

 

检查所有checked exception都被捕获或抛出

 

检查所有局部变量在使用前必项确定性赋值

 

 检查有返回值的方法必须确定性返回值

 

检查变量的确定性且不重复赋值

 

转换类型:(TransTypes)

 

使用com.sun.tools.javac.comp.TransTypes主要作用是将泛型java代码转换成普通的java代码

 

eg:

 

List<Integer> list = Arrays.asList(1, 2, 3);

 

int i = list.get(0);

 

转换后:

 

List list = Arrays.asList(1, 2, 3);

 

int i = (Integer)list.get(0);为了保证泛型的语义,增加了强制类型转换

 

 解除语法糖:(Lower)

 

使用com.sun.tools.javac.comp.Lower类

 

消除if(false){…}形式的无用代码

 

将含有语法糖的语法树改写为含有简单语言结构的语法树

 

eg

 

 具名内部类,匿名内部类,类字面量

 

自动装箱拆箱

 

断言

 

foreach循环

 

enum或String类型的switch(java7)

 

eg:

 

List<Integer> list = Arrays.asList(1, 2, 3);

 

int i = list.get(0);

 

转换后:

 

List list = Arrays.asList(//自动装箱拆箱

 

new Integer[]{

 

Integer.valueOf(1),

 

Integer.valueOf(2),

 

Integer.valueOf(3)

 

}

 

);

 

int i = ((Integer)list.get(0)).intValue();

 

 

 

生成字节码:(Gen)

 

使用com.sun.tool.javac.jvm.Gen

 

将实例成员初始化器收集到构造器中成为<init>()

 

将静态成员初始化器收集为<clinit>()

 

从抽象语法树生成字节码

 

后序遍历语法树

 

进行最后的少量代码转换

 

    String的+操作被生成为StringBuilder操作

 

    x++/x–在条件允许时被优化为++x/–x

 

    etc …

 

从符号表生成Class文件

 

    生成Class文件的结构信息

    生成元数据(包括常量池)

转载:http://beiden.me/archives/2660.htm

你可能感兴趣的:(Javac编译器源代码分析)