JVM的编译优化-前期

JAVA是将类文件编译后生成操作码交给解释器执行,所以是解释性语言。

面向栈的指令集和面向寄存器的指令集

java是通过操作码将数据压入/弹出到操作栈中进行操作,所以是面向栈的,而还有一种流派是直接生成本地代码调用寄存器的指令,
俩者的区别。

  • 面向栈:便于移植,代码简单,由于不依赖寄存器,支持寄存器不支持的功能。由于执行指令多所以性能差
  • 面向寄存器:不便于移植,功能依赖于CPU等硬件。性能好

javac编译的过程

编译过程

源码如下

编译过程

解析文件和添加符号表

  • 词法、语法分析:通过词法分析器和语法分析器生成抽象语法树
  • 输入到符号表:将语法树种的在javac源码就是enterTree过程,符号表是一个kv的数据结构,用于收集符号以及变量,在语义校验阶段用于校验语法和产生中间代码,目标代码生成阶段是分配符号内存的依据

注解处理器处理注解

JDK1.5之后支持了注解,实际上是一个个的语法插件,会对语法树进行读取、修改,如果对语法树进行修改,需要重新解析文件和添加符号表,称为Round。也就是图上的回环

语义分析与字节码生成

  • 标注检查:检查变量是否已经声明,类型与赋值类型是否匹配。
  • 数据及控制流分析:进一步对语法和语义做检查。注意局部变量设置为final的语义检查是在编译器的,因为局部变量没有该final的常量标志位,所以在编译后是否声明称final没有区别。
  • 解语法糖:泛型、自动装箱、拆箱等都需要在编译阶段还原。
  • 字节码生成:
    • 实例构造器init方法和类构造器clinit方法添加到语法树,将调用父类的实例构造器等方法收敛到这俩个方法中
    • 优化操作:将String的添加等操作改为StringBuffer.append

JAVA语法糖详解

泛型和类型擦除