1、JVM编译过程:
1)语义分析器:添加默认构造函数(MemberEnter中complete方法)、处理annotation(注解)(javacProcessingEnvironment类)、处理Attr(标注)(检查语义合法性并逻辑判断如变量的类型是否匹配、变量在使用前是否已经初始化、能够推导出泛型方法的参数类型、字符串厂里的合并)等、数据流分析(Flow类)(去掉无用的代码、变量的自动转换、去掉语法糖如将foreach转换成for循环)
2)代码生成器:生成最终的java字节码:i、将java方法中的代码块转成符合JVM语法的形式,JVM的操作是棘突栈的,所有的操作必须经过出战与入栈来完成 ii、按照JVM的文件格式将字节码输出到以class的文件夹中
3)编译过程用到访问者模式设计模式
2、编译指令
指令 |
操作数 |
解释 |
aload |
n |
将本地变量n放入栈顶中,n是一个引用,如果n是double类型,则指令是dload,其他类型类似 |
aload_0 |
|
将本地变量0放入栈顶中,变量0是一个引用,如果变量0是double类型,则指令是dload_0,其他类似 |
astore |
n |
将栈顶元素放入本地变量n中,n是个引用,若n是double类型,则指令是dstore,其他类似 |
astore_0 |
|
将栈顶元素放入本地变量0中,0是个引用,如果0是double类型,则指令是dstore_0,其他类型类似 |
dadd |
|
将栈顶俩个doublez型相加,结果压入栈顶,如果是俩个float类型相加,则指令是fadd,其他类型数值相加类似 |
dcmpg |
|
比较栈顶俩个double类型值大小,将1、0、-1结果压入栈顶,如果其中一个参数是NaN,则将1压入栈顶,如果指令是dcmpl,则将-1压入栈顶。如果比较float类型,则指令是fcmpg |
ddiv |
|
将栈顶俩个double类型值相除,结果压入栈顶,其他情况如上 |
dmul |
|
将栈顶俩个double值相乘,结果压入栈顶,其他情况如上 |
dneg |
|
将栈顶俩个double类型数值取负,结果压入栈顶,其他情况如上 |
drem |
|
将栈顶俩个double取模,结果压入栈顶,其他情况如上 |
dsub |
|
将栈顶俩个double值相减,结果压入栈顶,其他情况如上 |
i2b |
|
将栈顶int类型强制转成byte类型,结果压入栈顶 |
i2c |
|
将栈顶int类型强制转成char类型,结果压入栈顶 |
i2s |
|
将栈顶int类型强制转成short类型,结果压入栈顶 |
ior |
|
将栈顶俩个int类型相或,结果压入栈顶 |
ishr |
|
将int类型右移指定位数,结果压入栈顶 |
ishr |
|
将int类型左移指定位数 |
ixor |
|
将栈顶俩个int类型按位异或,结果压入栈顶 |
iushr |
|
将无符号int类型右移指定位数,结果压入栈顶 |
|
|
与常量有关的指令集 |
|
|
与java控制指令相关的指令集 |
|
|
与java数据类型转换相关的指令集 |
|
|
与java同步操作相关的指令集 与数组操作相关的指令集 |
aconst_null |
|
将Null压入栈顶 |
bipush |
n |
将单字节的常量值 -128~127压入栈顶· |
dconst_0 |
|
将栈顶压入一个double常量0 |
fconst_0 |
|
将栈顶压入一个float常量0 |
areturn |
|
返回一个引用 |
dreturn |
|
返回一个double类型数据 |
goto |
|
跳转到指定的偏移地址对应的指令 |
if_acmpeg |
|
比较栈顶俩引用数值,当结果相等时跳转,不相等时跳转指令是if_acmpne |
If_icmpne |
|
比较栈顶俩int数值,当结果等于0时跳转,大于等于0是if_icmpge,大于0是if_icmpgt,小于等于0是if_cmple,小于0是if_icmplt,当结果不等于0跳转是if_icmpne |
lookupswitch |
Tag1:loabel1 Tag2:loabel2 Default:labeln |
用于switch条件跳转 |
nop |
|
什么都不做 |
d2f |
|
将栈顶double元素类型转成float类型 |
monitorenter |
|
获得对象锁,用于同步方法或同步快,释放对象是monitorexit |
|
|
|
3、Class中的常量表示方式
1)utf8类型
2)Fieldref、Methodref类型表示
3)Class常量表示
4)NameAndType常量类型