Javac是java的编译器,负责将java源代码转化成符合java规范的ClassFile格式的字节码文件
程序入口调用过程
整个转化的入口在Main类中的main方法,之后调用到了JavaCompiler中的compile方法。
编译器前端
compile方法中首先用javacParser来进行编译器前端的工作,负责把java代码变成Token流,之后再把TokenSteam变成抽象语法树
java的ast长这个样子java language specification
编译器后端
之后在compile2方法中进行把一个parse好了的抽象语法树的一些后续操作,如attribute,data flow分析等等
ClassFile生成
在compile2方法中的调用了generate来对一个已经设置好属性和进行过各种分析和处理的语法树生成相应的ClassFile。其中,主要分为两个部分
Gen
这部分主要有com.sun.tools.javac.jvm.Gen类完成,Gen类集成自com.sun.tools.javac.tree.JCTree.Visitor类(一个定义了对所有Ast节点进行访问的方法的抽象类),负责访问对应的Ast的每个节点,生成字节码(待confirm)
调用过程如下,一层套一层说都不知道怎么说了,用这个类为例
import com.ipads.Persist;
import com.ipads.Root;
@Persist
public class Hello
{
@Persist
public String test = "hello world";
public static void main(String[] args)
{
@Root Hello test2 = new Hello();
test2.test = new String("javac");
System.out.println(test2.test);
}
}
generate -> 对所有的顶级CompileUnit调用genClass
genClass -> 对类中所有的method或field定义调用genDef
--------------目前节点-----------------
public <init>() {
super();
test = "hello world";
}
genDef -> 相应ast节点的accept方法,接受this对自己进行visit
accept -> 调用visitor相应的visitXXX方法,这里是Gen.visitMethodDef
Gen.visitMethodDef(JCMethodDef) -> Gen的genMethod方法
genMethod -> 如果有body,对body(Block)进行Gen.genStat
--------------目前节点-----------------
{
super();
test = "hello world";
}
genStat -> 直接调用genDef进行gen
genDef -> accept -> visitBlock
Gen.visitBlock(JCBlock) -> 调用Gen的genStats方法,把自己所有stats作为一个list传进去
genStats -> 对所有的stats依次调用genStat(这里是一个多参数版本的genStat,然而多的参数干什么的并不知道)
--------------目前节点-----------------
super();
genStat -> 做了一些看不懂的操作,之后调用两个参数的正常genStat
genStat -> genDef -> accept -> visitExec
Gen.visitExec(JCExpressionStatement) -> 看一下当前节点里面的expr有没有tag,有的话打上,没有的话不管了,之后对expr调用Gen.genExpr
--------------目前节点-----------------
super() // method invocation expression, without ;, is not a statement
genExpr -> 判断一下是不是常量,如果是的话用ClassReferenceVisitor这个类进行visit,不是的话用Gen进行visit,调用accept进行visit
accept -> visitApply -> genExpr && genArgs
--------------目前节点-----------------
super // JCIndent
genExpr -> apply -> visitIndent
Gen.visitIndent ->
Writer
这部分由writer类完成,负责将之前生成好的字节码和常量池等等在内存中的数据结构们按照ClassFile的格式打印到真正的ClassFile中。