aconst_null

压特殊的 null 对象引用入栈。

iconst_

作用压整型数字0,1,2,3,4,5 入栈

注意

压入栈的指令还有:

bipush 0; sipush 0; idc 0;

但这些指令相对于等同的 iconst_ 指令,效率更低,并且在 class 文件中占用更加多的字节

iconst_m1

将 -1 压入操作数栈

lconst_

lconst_0lconst_1

压长整型 long integer 0 或 1 入栈

注意

也可以用

ldc2_w 0

尽管这条指令占用更多的字节以及效率更低

fconst_

fconst_0fconst_1fconst_2

压单精度浮点数 0.0, 1.0 或 2.0 入栈

注意

你也可以用

ldc 0.0

尽管这条指令占用更多的字节以及效率更低

dconst_

dconst_0dconst_1

压双精度浮点数 0.0 或 1.0 入栈

注意

你也可以用

ldc2_w 0.0

尽管这条指令占用更多的字节以及效率更低

bipush

bipush

n 是一个 -128 <= n <= 127 的整数。压 1字节 有符号整数入栈。

注意

bipush 通常比 ldc 更高效。并且它在class文件中占用的字节数更少。

sipush

sipush

n 是一个 -32768 <= n <= 32767 的有符号整数。压 2字节 有符号整数入栈。

ldc

ldc

是一个int,或 floag,或 引号的 string。压一个字大小的常量入栈。

在字节码中, ldc 操作码后接着一个 8位 无符号的整数,这个整数是当前 class 的常量池项的索引。项是被标识为 CONSTRANT_IntegerCONSTRANT_FloatCONSTRANT_String

注意

当可能时,使用 bipushsipushconst 指令之一来代替 ldc ,因为它们通常更高效。

ldc_w

ldc_w

是一个 int, 或 float 或 引号的 string。压一个字大小的常量入栈(wide index)

注意

ldc_wldc 是相同的。区别在于:

ldc_w 使用的是 16-bit 索引,而 ldc 使用的是 8-bit 索引

ldc2_w

ldc2_w

是一个 long integer 或 double 数字。

在字节码中, ldc2_w 操作码后接着一个 16-bit 无符号的整数。这个整数是一个常量池中的索引项。项是标识为 CONSTRANT_DoubleCONSTRANT_Long 的项。

iload

iload => 这种是无符号整数,范围为 0~0xFF,即 0~255 或 wide iload => 这种是无符号整数,范围为 0~0xFFFF,即 0~65535

从本地变量 (local variable) (varnum是本地变量的号码) 获取 integer。即将本地变量 varnum 的值压入栈。

iload_

它等同于 iload ,但通常,它比 iload 更高效,并且在class文件中占用更少的字节数。

lload

lload => 这种是无符号整数,范围为 0~0xFF 或 wide lload => 这种是无符号整数,范围为 0~0xFFFE

从本地变量(local variable) 获取一个 long integer,然后将它压入栈

lload_

它等同于 lload ,但通常,它比 lload 更高效,并且在class文件中占用更少的字节数

注意

由于 long integer 是 64-bit 的,并且每一个本地变量最多持有32-bit,所以Java使用了连续2个本地变量, + 1 来保存一个 long 。因此, lload 通常是将 + 1 的本地变量压入栈。

fload

fload => 这是一个无符号数,范围为 0~0xFF 或 wide fload => 这是一个无符号数,范围为 0~0xFFFF

从本地变量 (local variable) (varnum是本地变量的号码) 获取 float。即将本地变量 varnum 的值压入栈。

fload_

它等同于 fload ,但通常,它比 fload 更高效,并且在class文件中占用更少的字节数

dload

dload => 这是一个无符号数,范围为 0~0xFF 或 wide dload => 这是一个无符号数,范围为 0~0xFFFE

从本地变量 (local variable) (varnum是本地变量的号码) 获取 double。即将本地变量 varnum 的值压入栈。

注意

由于 double 是 64-bit 的,并且每一个本地变量最多持有32-bit,所以Java使用了连续2个本地变量 + 1 来保存 double 。

因此, dload 通常是将 + 1 压入栈。

dload_

它等同于 dload ,但通常,它比 dload 更高效,并且在class文件中占用更少的字节数

aload

aload => 这是一个无符号数,范围为 0~0xFF 或 wide aload => 这是一个无符号数,范围为 0~0xFFFF

从本地变量(local variable)获取一个对象的引用,然后将它压入栈。

aload_

它等同于 aload ,但通常,它比 aload 更高效,并且在class文件中占用更少的字节数

aaload

从一个对象数组(array of objects)中获取一个对象引用(object reference),然后将它压入栈

aaload 之前,栈顶应该为:

index:数组索引 arrayref:数组对象的引用

aaload 之后,栈顶为:

arrayref[index]的值

所以,aaload之前,通常要准备好arrayref 和 index 的值压入栈。

iaload

从一个int数组(integer array)中获取一个int,然后将它压入栈。

laload

从一个long数组(long array)中获取一个long,然后将它压入栈。

daload

从一个double数组(double array)中获取一个double,然后将它压入栈。

baload

从一个字节数组(byte array)中获取一个字节,然后扩展它为一个 integer ,最后压它入栈。

它也用作从布尔数组中接收值。(Sun的实现中,boolean array 通常也是保存为 byte array的,每一个字节代表一个布尔值)

caload

从一个字符数组中获取一个字符,然后将它压入栈。

saload

从一个 short 数组中获取一个 short 。

istore

istore => 这是一个无符号数,范围为 0~0xFF 或 wide istore => 这是一个无符号数,范围为 0~0xFFFF

从栈顶弹出(pop)一个int,并且将它保存到本地变量 (local variable) 中。

istore_

istore_0 , istore_1istore_2istore_3

它等同于 istore ,通常该指令比 istore 更高效,并且在class文件中占用更少的字节数。

lstore

lstore => 这是一个无符号数,范围为 0~0xFF 或 wide lstore => 这是一个无符号数,范围为 0~0xFFFE

从栈顶弹出(pop)一个int,并且将它保存到本地变量 (local variable) 中。

注意

long 是 64-bit 的,并且每个本地变量最多只能拥有 32-bit,由于Java使用2个连续的本地变量 + 1 来表示一个 long。

因此, lstore 通常修改了 + 1 的值。

lstore_

lstore_0, lstore_1, lstore_1, lstore_2, lstore_3

它等同于 lstore ,通常该指令比 lstore 更高效,并且在class文件中占用更少的字节数。

fstore

fstore => 这是一个无符号数,范围为 0~0xFF 或 wide store => 这是一个无符号数,范围为 0~0xFFFF

从栈顶弹出(pop)一个float,并且将它保存到本地变量 (local variable) 中。

fstore_

fstore_0, fstore_1, fstore_1, fstore_2, fstore_3

它等同于 fstore ,通常该指令比 fstore 更高效,并且在class文件中占用更少的字节数。

dstore

dstore => 这是一个无符号数,范围为 0~0xFF 或 wide dstore => 这是一个无符号数,范围为 0~0xFFFE

从栈顶弹出(pop)一个double,并且将它保存到本地变量 (local variable) 中。

注意

double 是 64-bit 的,并且每个本地变量最多只能拥有 32-bit,由于Java使用2个连续的本地变量 + 1 来表示一个 long。

因此, dstore 通常修改了 + 1 的值。

dstore_

dstore_0, dstore_1, dstore_1, dstore_2, dstore_3

它等同于 dstore ,通常该指令比 dstore 更高效,并且在class文件中占用更少的字节数。

astore

astore => 这是一个无符号数,范围为 0~0xFF 或 wide astore => 这是一个无符号数,范围为 0~0xFFFF

从栈顶弹出(pop)一个对象引用,并且将它保存到本地变量 (local variable) 中。

astore_

astore_0, astore_1, astore_1, astore_2, astore_3

它等同于 astore ,通常该指令比 astore 更高效,并且在class文件中占用更少的字节数。

iastore

从栈中获取一个 int,并且将它保存到一个 int 数组对象中。

iastore 指令执行之前的栈: value index arrayref xxx

执行完之后: xxx

lastore

从栈中获取一个双字,long integer ,并且将它保存到一个 long integer 数组中。

lastore 指令执行之前的栈: value-word1 value-word2 index arrayref xxx

执行完之后: xxx

fastore

与 iastore 类似

dastore

与 lastore 类似

aastore

与 iastore 类似

castore

与 iastore 类似。 c 表示 character

sastore

与 iastore 类似. s 表示 short

pop

从栈顶中丢弃一个字(single-word)大小的数据。

pop2

从栈顶中丢弃两个字(two words)大小的数据。

dup

复制栈顶一个字(single-word)的数据,然后压它入栈。

即 pop 一次,push 两次

dup_x1

复制栈顶一个字(single-word)的数据,然后插入到原栈顶下面第二项中。

执行指令之前,栈顶: word1 word2 xxxx

执行完指令之后: word1 word2 word1 xxxx

dup_x2

复制栈顶一个字(single-word)的数据,然后插入到原栈顶下面第三项中。

执行指令之前,栈顶: word1 word2 word3 xxxx

执行完指令之后: word1 word2 word3 word1 xxxx

dup2

复制栈顶两个字(two-words)的数据,然后压它入栈。(比如2个int, 1个int和object引用,又或者是一个 double ,或一个 long)

dup2_x1

复制栈顶两个字(two-words)的数据,然后将复制的那个字(two-word)插入到原前一个字(previous single word)前面。

比如 dup2_x1 指令之前的栈为: word1 word2 word3 xxxx

执行完指令之后,栈为: word1 word2 word3 word1 word2 xxxx

dup2_x2

复制栈顶两个字(two-words)的数据,然后将复制的那个字(two-word)插入到原前两个字(previous two word)前面。

比如 dup2_x1 指令之前的栈为: word1 word2 word3 word4 xxxx

执行完指令之后,栈为: word1 word2 word3 word4 word1 word2 xxxx

swap

交换栈顶两个字的数据

指令执行之前: word1 word2 xxxx

指令执行完后: word2 word1 xxxx

iadd, isub, imul, idiv, irem

将栈顶两个数弹出(pop),然后将它们相加(减,乘,除,取模)的结果压入栈

ladd,lsub, lmul, ldiv, lrem

将栈顶两个 long integer 弹出,然后将它们相加(减,乘,除,取模)的结果压入栈。

指令前的栈: value1-word1 value1-word2 value2-word1 value2-word2 xxxx

指令执行后的栈: result-word1 result-word2 xxxx

fadd, fsub, fmul, fdiv, frem

将栈顶两个单精度浮点数弹出,然后将它们相加(减,乘,除,取模)的结果压入栈。

dadd, dsub, dmul, ddiv, drem

将栈顶两个双精度浮点数弹出,然后将它们相加(减,乘,除,取模)的结果压入栈。

指令前的栈: value1-word1 value1-word2 value2-word1 value2-word2 xxxx

指令后的栈: result-word1 result-word2 xxxx

ineg, lneg, fneg, dneg

将栈顶 int, long, float, double 弹出,取负后,再压入栈

ishl, lshl, ishr, lshr

将 int, long 左移或右移指定位数(有符号)。

栈前: value1 => 要位移的个数 value2 => 要进行位移的数 xxxx

栈后 result xxxx

例如, ishr ,它等同于 x / (2^n) ,n 就是 value1,x 就是 value2

iushr, lushr

它是无符号位移

iand, land, ior, lor, ixor, lxor

将栈顶两个 int 或 两个long 的值进行位与(或、异或)操作。

栈前: value1 value2 xxxx

栈后 result xxxx

iinc

iinc => varnum 是一个无符号数,范围为 0~0xFF, n 是一个有符号整数,范围为 -128~127 或 wide iinc => varnum 是一个无符号数,范围为 0~0xFFFF, n 是一个有符号整数,范围为 -32768 ~ 32767

表示将本地变量 (local variable) 序号为 varnum 的变量,增加 n (注意,n可以为负的,即减的意义)

i2l

将 int 转换为 long 。

栈前: int xxxx

栈后 long-word1 long-word2 xxxx

i2f

栈前

int xxxx

栈后

float xxxx

i2d

栈前 int xxxx

栈后 double-word1 double-word2 xxxx

l2i

栈前

long-word1 long-word2 xxxx

栈后

int xxxx

l2f

栈前 long-word1 long-word2 xxxx

栈后 float xxxx

l2d

栈前

long-word1 long-word2 xxxx

栈后

double-word1 double-word2 xxxx

f2i

栈前

float xxxx

栈后

int xxxx

f2l

栈前

float xxxx

栈后

long-word1 long-word2 xxxx

f2d

栈前

float xxxx

栈后

double-word1 double-word2 xxxx

d2i

栈前

double-word1 double-word2 xxxx

栈后

int xxxx

d2l

栈前

double-word1 double-word2 xxxx

栈后

long-world1 long-world2

d2f

栈前

double-word1 double-word2 xxxx

栈后

float xxxx

i2b

从栈顶中弹出一个 int,然后转换为有符号的字节(前8位保留,后24位丢弃,即后24位设置为0),然后将结果进行有符号扩展,最后将结果压入栈

注意:它可能会导致符号(正负)改变。

i2c

从栈顶中弹出一个 int,然后转换为一个 16位无符号字符。(后16位设置为0),然后将结果压入栈

i2s

从栈顶中弹出一个 int,然后转换为一个有符号的 short 。(后16位设置为0),然后将结果进行有符号扩展,最后将结果压入栈。

注意:它可能会导致符号(正负)改变。

lcmp

将栈顶两个 long 值弹出,然后比较它们的大小。如果相等,则将 0 压入栈。如果 value2 > value 1 ,则将 1 压入栈;如果 value1 > value 2 ,则将 -1 压入栈。

栈前: value1-word1 value1-word2 value2-word1 value2-word2 xxxx

栈后: int-result xxxx

fcmpl

单精度浮点数比较。(如果任一数字是 NaN,则压-1入栈)

栈前 value1 value2 xxxx

栈后 int-result xxxx

如果相等,则将 int 0 压入栈。如果 value2 > value 1 ,则将 1 压入栈; 如果 value1 > value2,则将 -1 压入栈。

fcmpg

与 fcmpl 相同。但如果任一数字是 NaN,则压1入栈。

dcmpl

双精度浮点比如(如果任一数字是 NaN,则压-1入栈)

栈前: value1-word1 value1-word2 value2-word1 value2-word2 xxxx

栈后 int-result xxxx

如果相等,则将 int 0 压入栈。如果 value2 > value 1 ,则将 1 压入栈; 如果 value1 > value2,则将 -1 压入栈。

dcmpg

与 dcmpl 相同。但如果任一数字是 NaN,则压1入栈。

ifeq

ifeq

如果栈顶的 int 为0,则跳转到 label 的位置。(弹出栈顶)

ifne

ifne

如果栈顶的 int 不为0,则跳转到 label 的位置。(弹出栈顶)

ifge

ifge

如果栈顶的 int 大于等于 0,则跳转到 label 的位置。(弹出栈顶)

ifgt

ifgt

如果栈顶的 int 大于 0,则跳转到 label 的位置。(弹出栈顶)

ifle

ifle

如果栈顶的 int 小于等于 0,则跳转到 label 的位置。(弹出栈顶)

if 与 cmp 指令结合

它们都是以 int 来比较(弹出栈顶两个 int)

if_icmpeq => 比较,如果等于0(即相等),则跳转 if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple

if_acmpeq => 比较两个引用型,如果相等,则跳转 if_acmpne => 比较两个引用型,如果不相等,则跳转

goto

goto

跳转到 label

jsr

jump to subroutine

jsr

栈前: xxx

栈后 return-address xxx

它通常用来实现 Java 中的 finally 子句。

ret

ret => 它是一个无符号整数,范围为 0~0xFF 或 wide ret => 它是一个无符号整数,范围为 0~0xFFFF

它用于从 subroutine (即用 jsr 指令调用的)返回。

tableswitch

用于执行计算比较跳转

tableswitch [] default :

栈前: val xxxx

栈后 xxxx

low 是一个有符号 32-bit 整数。

lookupswitch

用于执行高效的 比较-然后-跳转。通常是 switch 语句。

lookupswitch : : : default :

key1, key2 都是 32-bit 整数

栈前: item xxxx

栈后 xxxx

ireturn

从方法中返回 integer 结果。

栈前: return-value xxxx

栈后 xxxx

它从栈顶中弹出一个 int ,然后将它压入调用者(例如,使用 invokevirtual, invokespecial, invokestatic or invokeinterface 来调用当前正执行的方法)的操作数栈中。当前正执行的方法的其他操作数栈都会被丢弃。

lreturn

与 ireturn 相同。只是它返回的是 long (注意,它要占用2个32-bit)

freturn

与 ireturn 相同。只是它返回的是 float

dreturn

与 ireturn 相同。只是它返回的是 double

areturn

与 ireturn 相同。只是它返回的是 对象引用.

栈前: objectref xxxx

栈后 xxxx

return

从方法中返回。方法的返回类型为 void。

getstatic

获取静态域 static field

getstatic

它会从栈顶中的 objectref 引用弹出,然后从 objectref 中获取以 field-spec 标识的静态域,最后将这个值压入栈(一个字或双字,双字的情况,比如 double, long 类型)

栈前: xxxx

栈后 value xxxx

或 value-word1 value-word2 xxxx

putstatic

putstatic

为静态域设置值(值是从栈顶中的一个字或双字获取)

栈前: value xxxx

栈后 xxxx

栈前: value-word1 value-word2 xxxx

栈后: xxxx

getfield

getfield

例如: getfield java/lang/System/out Ljava/io/PrintStream;

从栈顶中弹出对象的引用(objectref),然后获取它的指定字段,最后将字段的值(一个字或双字)压入栈。

栈前: objectref xxxx

栈后 value xxxx

栈前: objectref xxxx

栈后: value-word1 value-word2 xxxx

putfield

putfield

为实例对象设置值。

栈前: value objectref xxxx

栈后: xxxx

栈前: value-word1 value-word2 objectref xxxx

栈后: xxxx

invokevirtual

调用实例方法

invokevirtual

栈前: arg1 arg2 … argN objectref xxxx

栈后: result xxxx

invokespecial

invokespecial

调用属于指定 class 的方法(比如构造函数, this 的私有方法, this 父类的方法等)

栈前:

argN … arg2 arg1 objectref xxxx

栈后: [result] xxxx

invokestatic

invokestatic

调用一个类的静态方法

栈前: argN … arg2 arg1 objectref xxxx

栈后: [result] xxxx

invokeinterface

调用一个接口方法

invokeinterface

栈前: argN … arg2 arg1 objectref xxxx

栈后: [result] xxxx

new

new

创建一个对象

栈前: xxxx

栈后: objectref xxxx

newarray

newarray

type 可以是以下之一: boolean, char, float, double, byte, short, int, long

栈前: n xxxx

栈后: arrayref xxxx

anewarray

anewarray

type 是一个 class 或 interface 名。

栈前: size xxxx

栈后: arrayref xxxx

arraylength

获取数组长度

栈前: arrayref xxxx

栈后: length xxxx

athrow

抛出一个异常。

栈前: objectref[这是一个异常类型对象, throwable 或它的子类] xxxx

栈后: xxxx

checkcast

检查对象或数组的类型

checkcast

栈前: objectref xxxx

栈后: objectref xxxx

检查栈顶的操作数(一个对象或数组的引用)是否可以转换为指定的类型。

instanceof

instanceof

测试一个对象是否某个类的实例

栈前: objectref xxxx

栈后: int-result xxxx

如果是,则int-result为1,否则为0

monitorenter

进入一个同步的代码区域

栈前: objectref xxxx

栈后: xxxx

monitorexit

离开一个同步的代码区域

栈前: objectref xxxx

栈后: xxxx

nop

这个条指令并不会做任何事。编译器有时会有了调试,测试或时序的目的而生成 nop

参考资料

cs.au.dk