JVM九:class字节码指令集

一:字节码与数据类型

    Java虚拟机的指令由一个字节长度,代表着某种特定操作含义的数字(称为操作码)以及跟其随后的零至多个代表此操作所需参数(称为操作数)而构成。Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数指令都不包含操作数。因为字节码指令只有一个字节,所以指令集的操作码总数不可能超过256条

   在Java虚拟机中,大多数的指令都包含了其对操作所对应的数据类型信息。对于大部分与数据类型相关的字节码指令,他们的操作码助记符中都有特殊的字符来表明专门为哪种数据类型服务。i代表int l代表long,s代表short,b代表byte,c代表char,f代表float,a代表reference.

二:加载和存储指令

   加载存储指令用于将数据在帧栈中的局部变量表和操作数栈进行来回传输。

①将一个局部变量加载到操作栈:iload,iload<n>,lload,lload<n>,fload,fload<n>,dload,dload<n>,aload,aload<n>

②将一个数值从操作数栈存储到局部变量表中:istore,istore<n>,lstore,lstore<n>,fstore,fstore<n>,dstore,dstore<n>,adore,adore<n>

③将一个常量加载到操作数栈中:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_m1,iconst_<i>,fconst_<i>,dconst_<i>.

④扩充局部变量的访问索引的指令。wide.

指令具体含义如下表所示:

指令码

助记符

功能描述

0x00

nop

无操作

0x01

aconst_null

指令格式:  aconst_null

功能描述:  null进栈。

指令执行前

指令执行后

栈底

...

...

null

栈顶

注意:JVM并没有为null指派一个具体的值。

0x02

iconst_m1

int型常量值-1进栈

0x03

iconst_0

int型常量值0进栈

0x04

iconst_1

int型常量值1进栈

0x05

iconst_2

int型常量值2进栈

0x06

iconst_3

int型常量值3进栈

0x07

iconst_4

int型常量值4进栈

0x08

iconst_5

int型常量值5进栈

0x09

lconst_0

long型常量值0进栈

0x0A

lconst_1

long型常量值1进栈

0x0B

fconst_0

float型常量值0进栈

0x0C

fconst_1

float型常量值1进栈

0x0D

fconst_2

float型常量值2进栈

0x0E

dconst_0

double型常量值0进栈

0x0F

dconst_1

double型常量值1进栈

0x10

bipush

将一个byte型常量值推送至栈顶

0x11

sipush

将一个short型常量值推送至栈顶

0x12

ldc

将int、float或String型常量值从常量池中推送至栈顶

0x13

ldc_w

将int、float或String型常量值从常量池中推送至栈顶(宽索引)

0x14

ldc2_w

将long或double型常量值从常量池中推送至栈顶(宽索引)

0x15

iload

指定的int型局部变量进栈

0x16

lload

指定的long型局部变量进栈

0x17

fload

指定的float型局部变量进栈

0x18

dload

指定的double型局部变量进栈

0x19

aload

指令格式:  aload index

功能描述:  当前frame的局部变量数组中下标为

           index的引用型局部变量进栈

指令执行前

指令执行后

栈底

...

...

objectref

栈顶

index  :  无符号一byte整型。和wide指令联用,

           可以使index为两byte。

0x1A

iload_0

第一个int型局部变量进栈

0x1B

iload_1

第二个int型局部变量进栈

0x1C

iload_2

第三个int型局部变量进栈

0x1D

iload_3

第四个int型局部变量进栈

0x1E

lload_0

第一个long型局部变量进栈

0x1F

lload_1

第二个long型局部变量进栈

0x20

lload_2

第三个long型局部变量进栈

0x21

lload_3

第四个long型局部变量进栈

0x22

fload_0

第一个float型局部变量进栈

0x23

fload_1

第二个float型局部变量进栈

0x24

fload_2

第三个float型局部变量进栈

0x25

fload_3

第四个float型局部变量进栈

0x26

dload_0

第一个double型局部变量进栈

0x27

dload_1

第二个double型局部变量进栈

0x28

dload_2

第三个double型局部变量进栈

0x29

dload_3

第四个double型局部变量进栈

0x2A

aload_0

指令格式:aload_0

该指令的行为类似于aload指令index为0的情况。

0x2B

aload_1

同上

0x2C

aload_2

同上

0x2D

aload_3

同上

0x2E

iaload

指定的int型数组的指定下标处的值进栈

0x2F

laload

指定的long型数组的指定下标处的值进栈

0x30

faload

指定的float型数组的指定下标处的值进栈

0x31

daload

指定的double型数组的指定下标处的值进栈

0x32

aaload

指令格式:  aaload

功能描述:  栈顶的数组下标(index)、数组引用

           (arrayref)出栈,并根据这两个数值

           取出对应的数组元素值(value)进栈。

抛出异常:  如果arrayref的值为null,会抛出

           NullPointerException。

           如果index造成数组越界,会抛出

           ArrayIndexOutOfBoundsException。

指令执行前

指令执行后

栈底

...

...

arrayref

value

index

栈顶

index      :  int类型

arrayref   :  数组的引用

0x33

baload

指定的boolean或byte型数组的指定下标处的值进栈

0x34

caload

指定的char型数组的指定下标处的值进栈

0x35

saload

指定的short型数组的指定下标处的值进栈

0x36

istore

将栈顶int型数值存入指定的局部变量

0x37

lstore

将栈顶long型数值存入指定的局部变量

0x38

fstore

将栈顶float型数值存入指定的局部变量

0x39

dstore

将栈顶double型数值存入指定的局部变量

0x3A

astore

指令格式:  astore index

功能描述:  将栈顶数值(objectref)存入当前

           frame的局部变量数组中指定下标

           (index)处的变量中,栈顶数值出栈。

指令执行前

指令执行后

栈底

...

...

objectref

栈顶

index  :  无符号一byte整数。该指令和wide联

           用,index可以为无符号两byte整数。

0x3B

istore_0

将栈顶int型数值存入第一个局部变量

0x3C

istore_1

将栈顶int型数值存入第二个局部变量

0x3D

istore_2

将栈顶int型数值存入第三个局部变量

0x3E

istore_3

将栈顶int型数值存入第四个局部变量

0x3F

lstore_0

将栈顶long型数值存入第一个局部变量

0x40

lstore_1

将栈顶long型数值存入第二个局部变量

0x41

lstore_2

将栈顶long型数值存入第三个局部变量

0x42

lstore_3

将栈顶long型数值存入第四个局部变量

0x43

fstore_0

将栈顶float型数值存入第一个局部变量

0x44

fstore_1

将栈顶float型数值存入第二个局部变量

0x45

fstore_2

将栈顶float型数值存入第三个局部变量

0x46

fstore_3

将栈顶float型数值存入第四个局部变量

0x47

dstore_0

将栈顶double型数值存入第一个局部变量

0x48

dstore_1

将栈顶double型数值存入第二个局部变量

0x49

dstore_2

将栈顶double型数值存入第三个局部变量

0x4A

dstore_3

将栈顶double型数值存入第四个局部变量

0x4B

astore_0

指令格式:  astore_0

功能描述:  该指令的行为类似于astore指令index

           为0的情况。

0x4C

astore_1

同上

0x4D

astore_2

同上

0x4E

astore_3

同上

0x4F

iastore 

将栈顶int型数值存入指定数组的指定下标处

0x50

lastore

将栈顶long型数值存入指定数组的指定下标处

0x51

fastore

将栈顶float型数值存入指定数组的指定下标处

0x52

dastore

将栈顶double型数值存入指定数组的指定下标处

0x53

aastore

指令格式:  aastore

功能描述:  根据栈顶的引用型数值(value)、数组下

           标(index)、数组引用(arrayref)出

           栈,将数值存入对应的数组元素中。

抛出异常:  如果value的类型和arrayref所引用

           的数组的元素类型不兼容,会抛出抛出

           ArrayStoreException。

           如果index造成数组越界,会抛出

           ArrayIndexOutOfBoundsException。

           如果arrayref值为null,会抛出

           NullPointerException。

指令执行前

指令执行后

栈底

...

...

arrayref

index

value

栈顶

arrayref   :  必须是对数组的引用

index      :  int类型

value      :  引用类型

0x54

bastore

将栈顶boolean或byte型数值存入指定数组的指定下标处

0x55

castore

将栈顶char型数值存入指定数组的指定下标处

0x56

sastore

将栈顶short型数值存入指定数组的指定下标处

三:运算指令

   运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。注意:由于没有直接支持byte,short,char和boolean类型的算术运算指令,对这种类型直接转换为int进行运算。特别需要注意的是:数据运算可能会导致溢出对象,Java虚拟机在整数没有定义数据异常,所以整数异常不报异常,注意在编程中范围。

加法指令:iadd,ladd,fadd,dadd

减法指令:isub,lsub,fsub,dsub

乘法指令:imul,lmul,fmul,dmul

除法指令:idiv,ldiv,fdiv,ddiv

求于指令:irem,lrem,frem,drem

取反指令:ineg,lneg,fneg,dneg

位移指令:iishl,lishl,fishl,dishl

按位或指令:ior,lor

按位与指令:land,land

按位异或指令:ixor,lxor

局部变量自增指令:inc

比较指令:dcmpg,dcmpl,fcmpg,fcmpl,lcmp

运算指令比较容易理解,这里不详细介绍了。。。。。

四:类型转换指令

   类型转换指令可以将两种不同的数值类型进行相互转换,一般用于实现用户代码中的显式类型转换操作。

i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l和d2f.分为宽化类型转换和窄化类型转换。

五:对象创建与访问指令

  虽然类实例和数组都是对象,但Java虚拟机对类实例和数组的创建与操作使用了不同的字节码指令。

创建类实例的指令:new

创建数组的指令:newarray,anewarray,multianewarray

访问类字段:getField,putField(非static字段),getStatic,putStatic(static字段)

把一个数组元素加载到操作数栈的指令:baload,caload,saload,iaload,laload,faload,daload,aaload.

把一个栈值元素存储到数组元素中:bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore.

取数组长度的指令:arrayLength

检查类实例类型的指令:instanceof

new

创建一个对象,并且其引用进栈

0xBC

newarray

创建一个基本类型数组,并且其引用进栈

0xBD

anewarray

指令格式:  anewarray index1 index2

功能描述:  栈顶数值(count)作为数组长度,创建

           一个引用 型数组。栈顶数值出栈,数组引

           用进栈。

抛出异常:  如果count小于0,会抛出

           NegativeArraySizeException

指令执行前

指令执行后

栈底

...

...

count

arrayref

栈顶

count      :  int类型。

arrayref   :  对所创建的数组的引用。

0xBE

arraylength

指令格式:  arraylength

功能描述:  栈顶的数组引用(arrayref)出栈,该

           数组的长度进栈。

抛出异常:  如果arrayref的值为null,会抛出

           NullPointerException。

指令执行前

指令执行后

栈底

...

...

arrayref

length

栈顶

arrayref   :  数组引用

length     :  数组长度

五:操作数管理指令

如同操作一个普通数据结构中的堆栈那样,Java虚拟机提供了一些用于直接操作操作数栈的指令

将操作数栈的栈顶一个或两个出栈:pop,pop2

复制栈顶一个或两个数值并将赋制值或双份的复制值重新压入栈顶:dup,dup2,dup_x1,dup2_x1,du[_x2,dup2_x2.

0x59

dup

复制栈顶数值,并且复制值进栈

0x5A

dup_x1

复制栈顶数值,并且复制值进栈2次

0x5B

dup_x2

复制栈顶数值,并且复制值进栈2次或3次

0x5C

dup2

复制栈顶一个(long、double型的)或两个(其它类型的)数值,并且复制值进栈

0x5D

dup2_x1

0x5E

dup2_x2

六:控制转移指令

条件分支:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull,if_icmpeq,if_icmpne,ificmplt,ificmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne

复合条件分支:tableswitch,lookupswitch

无条件分支:goto,goto_w,jsr,jsr_w,ret

0x99

ifeq

当栈顶int型数值等于0时跳转

0x9A

ifne

当栈顶int型数值不等于0时跳转

0x9B

iflt

当栈顶int型数值小于0时跳转

0x9C

ifge

当栈顶int型数值大于等于0时跳转

0x9D

ifgt

当栈顶int型数值大于0时跳转

0x9E

ifle

当栈顶int型数值小于等于0时跳转

0x9F

if_icmpeq

比较栈顶两int型数值大小,当结果等于0时跳转

0xA0

if_icmpne

比较栈顶两int型数值大小,当结果不等于0时跳转

0xA1

if_icmplt

比较栈顶两int型数值大小,当结果小于0时跳转

0xA2

if_icmpge

比较栈顶两int型数值大小,当结果大于等于0时跳转

0xA3

if_icmpgt

比较栈顶两int型数值大小,当结果大于0时跳转

0xA4

if_icmple

比较栈顶两int型数值大小,当结果小于等于0时跳转

0xA5

if_acmpeq

比较栈顶两引用型数值,当结果相等时跳转

0xA6

if_acmpne

比较栈顶两引用型数值,当结果不相等时跳转

0xA7

goto

无条件跳转

0xA8

jsr

跳转至指定16位offset位置,并将jsr下一条指令地址压入栈顶

0xA9

ret

返回至局部变量指定的index的指令位置(通常与jsr、jsr_w联合使用)

0xAA

tableswitch

用于switch条件跳转,case值连续(可变长度指令)

0xAB

lookupswitch

用于switch条件跳转,case值不连续(可变长度指令)

0xAC

ireturn

当前方法返回int

0xAD

lreturn

当前方法返回long

0xAE

freturn

当前方法返回float

0xAF

dreturn

当前方法返回double

0xB0

areturn

指令格式:  areturn

功能描述:  从方法中返回一个对象的引用。

抛出异常:  如果当前方法是synchronized方法,

           并且当前线程不是改方法的锁的拥有者,

           会抛出

           IllegalMonitorStateException。

          

指令执行前

指令执行后

栈底

...

objectref

栈顶

objectref  :  被返回的对象引用。

0xB1

return

当前方法返回void

七:异常处理指令

Java中的显式抛出异常的操作(throw)都由athrow指令来实现。
整数运算中如果除数为0,则会在idiv或者ldiv中抛出ArithmeticException异常。

八:同步指令

同步一段指令集序列通常是由java语言中的synchronized语句块来表示,JVM指令集中有monitorenter和monitorexit两条指令来支持synchronized关键字的语义。

Java代码段有方法同步和代码同步,其中方法同步可有方法表结构的ACC_SYNCHRONIZED可知用户声明为同步方法。代码块则是由monitorenter和monitorexit支持,通过管程的方式进行同步。

猜你喜欢

转载自blog.csdn.net/weixin_40234548/article/details/81533673