「Java」- 虚拟机指令

  CREATED BY JENKINSBOT

简述

每个指令的长度为:1BYTE、0~255、0x00~0xFF

一、未归类系列

此系列暂未归类。

二、const系列

该系列命令主要:负责把简单的数值类型送到栈顶。该系列命令不带参数。注意:只把简单的数值类型送到栈顶时,才使用如下的命令。
比如:对应int型,只能把-1,0,1,2,3,4,5送到栈顶(分别采用iconst_m1,iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, iconst_5)
对于int型及其他的数值,使用push系列命令(比如bipush)。

三、push系列

该系列命令负责把一个整形数字(长度比较小)送到到栈顶。该系列命令有一个参数,用于指定要送到栈顶的数字。
注意该系列命令只能操作一定范围内的整形数值,超出该范围的使用将使用ldc命令系列。

四、ldc系列

该系列命令:负责把数值常量String常量从常量池中推至栈顶。该命令后面需要给一个表示常量在常量池中位置(编号)的索引值,
哪些常量是放在常量池呢?比如:

	final static int id = 32768;
	final static float double = 6.5;

除了const系列命令和push系列命令操作范围之外的数值类型常量,都放在常量池中.
另外,所有不是通过new创建的String都是放在常量池中的。

五、load系列

5.1、load系列A
该系列命令负责把本地变量的送到栈顶。这里的本地变量不仅可以是数值类型,还可以是引用类型。
对于前四个本地变量可以采用iload_0,iload_1,iload_2,iload_3(它们分别表示第0,1,2,3个整形变量)这种不到参数的简化命令形式。
对于第4以上的本地变量将使用iload命令这种形式,在它后面给一参数,以表示是对第几个(从0开始)本类型的本地变量进行操作。
对本地变量所进行的编号,是对所有类型的本地变量进行的(并不按照类型分类)。
对于非静态函数,第一变量是this,即其对于的操作是aload_0.
还有函数传入参数也算本地变量,在进行编号时,它是先于函数体的本地变量的。

5.2、load系列B
该系列命令负责把数组的某项送到栈顶。该命令根据栈里内容来确定对哪个数组的哪项进行操作。
比如,如果有成员变量:final String names[]={“robin”,”hb”};
那么这句话:String str=names[0];对应的指令为
17:
aload_0 //将this引用推至栈顶,即压入栈。
18:
getfield #5; Field names:[Ljava/lang/String;将栈顶的指定的对象的第5个实例域(Field)的值(这个值可能是引用,这里就是引用)压入栈顶
21:
iconst_0 //数组的索引值(下标)推至栈顶,即压入栈
22:
aaload //根据栈里内容来把name数组的第一项的值推至栈顶
23:
astore 5 //把栈顶的值存到str变量里。因为str在我的程序中是其所在非静态函数的第5个变量(从0开始计数),

六、store系列

6.1、store系列A
该系列命令负责把栈顶的值存入本地变量。这里的本地变量不仅可以是数值类型,还可以是引用类型。
如果是把栈顶的值存入到前四个本地变量的话,采用的是istore_0,istore_1,istore_2,istore_3(它们分别表示第0,1,2,3个本地整形变量)这种不到参数的简化命令形式。如果是把栈顶的值存入到第四个以上本地变量的话,将使用istore命令这种形式,在它后面给一参数,以表示是把栈顶的值存入到第几个(从0开始)本地变量中。
对本地变量所进行的编号,是对所有类型的本地变量进行的(并不按照类型分类)。
对于非静态函数,第一变量是this,它是只读的.
还有函数传入参数也算本地变量,在进行编号时,它是先于函数体的本地变量的。

6.2、store系列B
该系列命令负责把栈顶项的值存到数组里。该命令根据栈里内容来确定对哪个数组的哪项进行操作。
比如,如下代码:
int moneys[]=new int[5];
moneys[1]=100;
其对应的指令为:
49:
iconst_5
50:
newarray int
52:
astore 11
54:
aload
11
56:
iconst_1
57:
bipush
100
59:
iastore
60:
lload 6 //因为str在我的程序中是其所非静态在函数的第6个变量(从0开始计数).

七、pop系列

该系列命令似乎只是简单对栈顶进行操作,更多详情待补充。

八、栈顶元素数学操作及移位操作系列

该系列命令用于对栈顶元素行数学操作,和对数值进行移位操作。移位操作的操作数和要移位的数都是从栈里取得。

九、自增减指令

该指令用于对本地(局部)变量进行自增减操作。该指令第一参数为本地变量的编号,第二个参数为自增减的数量。
比如对于代码:
int d=10;
d++;
d+=2;
d–;
其指令为:
2:
bipush 10
4:
istore_2//在我的程序中是其所在非静态函数的第2个变量(从0开始计数).
5:
iinc 2, 1//在我的程序中是其所在非静态函数的第2个变量(从0开始计数).
8:
iinc 2, 2
11: iinc
2, -1
对本地变量所进行的编号,是对所有类型的本地变量进行的(并不按照类型分类)。
对于非静态函数,第一变量是this,它是只读的.还有函数传入参数也算本地变量,在进行编号时,它是先于函数体的本地变量的。

十、类型转化系列

该系列指令负责对栈顶数值类型进行类型转化,并把结果压入栈顶。

十二、比较指令系列

该系列指令用于对栈顶非int型元素进行比较,并把结果压入栈顶。

十三、有条件跳转指令系列

该系列指令用于对栈顶int型元素进行比较,根据结果进行跳转。第一个参数为要跳转到的代码的地址(这里的地址是指其指令在函数内是第几个指令)。注意对于boolean型,其实是把它当做int型来处理的。另外对于引用比较使用的时,其实是对存储的对象的地址进行比较。

十四、无条件跳转指令系列

该系列指令用于指令的跳转。

十五、返回(return)指令系列

该系列指令用于从函数中返回。如果有返回值的话,都把函数的返回值放在栈道中,以便它的调用方法取得它。

areturn
dreturn
freturn
ireturn
lreturn
return

十六、域操作指令系列

该系列指令用于对静态域和非静态域进行读写。该系列命令需要跟一个表明域编号的参数,

十七、方法操作命令系列

该系列指令用于对静态方法和非静方法进行调用。该系列命令需要跟一个表明方法编号的参数。
如果方法有传入参数的话,则需要先压栈到栈顶。另外,方法的返回参数是保存到栈顶的,因此我们可以通过栈道值取得方法的返回值。

十八、未归类系列

此系列暂未归类。

十九、new及数组系列

该系列用于创建一个对象和数组。

二十、异常(throw)抛出指令

用于抛出异常。

athrow

二十一、对象操作指令

该系列指令用于操作对象。

二十二、未归类系列C

此系列暂未归类。

二十三、new多维数组系列

二十四、有条件跳转指令系列

该系列用于根据引用是否为空,来进行相应的指令跳转。

二十五、无条件跳转指令系列

该系列指令用于进行无条件指令跳转。

参考文献

JVM指令详解(上): http://blog.csdn.net/hudashi/article/details/7062675
JVM指令详解(下): http://blog.csdn.net/hudashi/article/details/7062781
【JVM系列】Java 虚拟机指令操作码的映射表: http://blog.csdn.net/hp910315/article/details/50497513
Java字节码指令集的使用详细: http://www.jb51.net/article/36407.htm
java反汇编及JVM指令集(指令码、助记符、功能描述): http://blog.csdn.net/sum_rain/article/details/39892219