JVM 指令

阅读更多

 

字节码

 

  enum Code {
    _illegal              =  -1,

    // Java bytecodes
    _nop                  =   0, // 0x00
    _aconst_null          =   1, // 0x01
    _iconst_m1            =   2, // 0x02
    _iconst_0             =   3, // 0x03
    _iconst_1             =   4, // 0x04
    _iconst_2             =   5, // 0x05
    _iconst_3             =   6, // 0x06
    _iconst_4             =   7, // 0x07
    _iconst_5             =   8, // 0x08
    _lconst_0             =   9, // 0x09
    _lconst_1             =  10, // 0x0a
    _fconst_0             =  11, // 0x0b
    _fconst_1             =  12, // 0x0c
    _fconst_2             =  13, // 0x0d
    _dconst_0             =  14, // 0x0e
    _dconst_1             =  15, // 0x0f
    _bipush               =  16, // 0x10
    _sipush               =  17, // 0x11
    _ldc                  =  18, // 0x12
    _ldc_w                =  19, // 0x13
    _ldc2_w               =  20, // 0x14
    _iload                =  21, // 0x15
    _lload                =  22, // 0x16
    _fload                =  23, // 0x17
    _dload                =  24, // 0x18
    _aload                =  25, // 0x19
    _iload_0              =  26, // 0x1a
    _iload_1              =  27, // 0x1b
    _iload_2              =  28, // 0x1c
    _iload_3              =  29, // 0x1d
    _lload_0              =  30, // 0x1e
    _lload_1              =  31, // 0x1f
    _lload_2              =  32, // 0x20
    _lload_3              =  33, // 0x21
    _fload_0              =  34, // 0x22
    _fload_1              =  35, // 0x23
    _fload_2              =  36, // 0x24
    _fload_3              =  37, // 0x25
    _dload_0              =  38, // 0x26
    _dload_1              =  39, // 0x27
    _dload_2              =  40, // 0x28
    _dload_3              =  41, // 0x29
    _aload_0              =  42, // 0x2a
    _aload_1              =  43, // 0x2b
    _aload_2              =  44, // 0x2c
    _aload_3              =  45, // 0x2d
    _iaload               =  46, // 0x2e
    _laload               =  47, // 0x2f
    _faload               =  48, // 0x30
    _daload               =  49, // 0x31
    _aaload               =  50, // 0x32
    _baload               =  51, // 0x33
    _caload               =  52, // 0x34
    _saload               =  53, // 0x35
    _istore               =  54, // 0x36
    _lstore               =  55, // 0x37
    _fstore               =  56, // 0x38
    _dstore               =  57, // 0x39
    _astore               =  58, // 0x3a
    _istore_0             =  59, // 0x3b
    _istore_1             =  60, // 0x3c
    _istore_2             =  61, // 0x3d
    _istore_3             =  62, // 0x3e
    _lstore_0             =  63, // 0x3f
    _lstore_1             =  64, // 0x40
    _lstore_2             =  65, // 0x41
    _lstore_3             =  66, // 0x42
    _fstore_0             =  67, // 0x43
    _fstore_1             =  68, // 0x44
    _fstore_2             =  69, // 0x45
    _fstore_3             =  70, // 0x46
    _dstore_0             =  71, // 0x47
    _dstore_1             =  72, // 0x48
    _dstore_2             =  73, // 0x49
    _dstore_3             =  74, // 0x4a
    _astore_0             =  75, // 0x4b
    _astore_1             =  76, // 0x4c
    _astore_2             =  77, // 0x4d
    _astore_3             =  78, // 0x4e
    _iastore              =  79, // 0x4f
    _lastore              =  80, // 0x50
    _fastore              =  81, // 0x51
    _dastore              =  82, // 0x52
    _aastore              =  83, // 0x53
    _bastore              =  84, // 0x54
    _castore              =  85, // 0x55
    _sastore              =  86, // 0x56
    _pop                  =  87, // 0x57
    _pop2                 =  88, // 0x58
    _dup                  =  89, // 0x59
    _dup_x1               =  90, // 0x5a
    _dup_x2               =  91, // 0x5b
    _dup2                 =  92, // 0x5c
    _dup2_x1              =  93, // 0x5d
    _dup2_x2              =  94, // 0x5e
    _swap                 =  95, // 0x5f
    _iadd                 =  96, // 0x60
    _ladd                 =  97, // 0x61
    _fadd                 =  98, // 0x62
    _dadd                 =  99, // 0x63
    _isub                 = 100, // 0x64
    _lsub                 = 101, // 0x65
    _fsub                 = 102, // 0x66
    _dsub                 = 103, // 0x67
    _imul                 = 104, // 0x68
    _lmul                 = 105, // 0x69
    _fmul                 = 106, // 0x6a
    _dmul                 = 107, // 0x6b
    _idiv                 = 108, // 0x6c
    _ldiv                 = 109, // 0x6d
    _fdiv                 = 110, // 0x6e
    _ddiv                 = 111, // 0x6f
    _irem                 = 112, // 0x70
    _lrem                 = 113, // 0x71
    _frem                 = 114, // 0x72
    _drem                 = 115, // 0x73
    _ineg                 = 116, // 0x74
    _lneg                 = 117, // 0x75
    _fneg                 = 118, // 0x76
    _dneg                 = 119, // 0x77
    _ishl                 = 120, // 0x78
    _lshl                 = 121, // 0x79
    _ishr                 = 122, // 0x7a
    _lshr                 = 123, // 0x7b
    _iushr                = 124, // 0x7c
    _lushr                = 125, // 0x7d
    _iand                 = 126, // 0x7e
    _land                 = 127, // 0x7f
    _ior                  = 128, // 0x80
    _lor                  = 129, // 0x81
    _ixor                 = 130, // 0x82
    _lxor                 = 131, // 0x83
    _iinc                 = 132, // 0x84
    _i2l                  = 133, // 0x85
    _i2f                  = 134, // 0x86
    _i2d                  = 135, // 0x87
    _l2i                  = 136, // 0x88
    _l2f                  = 137, // 0x89
    _l2d                  = 138, // 0x8a
    _f2i                  = 139, // 0x8b
    _f2l                  = 140, // 0x8c
    _f2d                  = 141, // 0x8d
    _d2i                  = 142, // 0x8e
    _d2l                  = 143, // 0x8f
    _d2f                  = 144, // 0x90
    _i2b                  = 145, // 0x91
    _i2c                  = 146, // 0x92
    _i2s                  = 147, // 0x93
    _lcmp                 = 148, // 0x94
    _fcmpl                = 149, // 0x95
    _fcmpg                = 150, // 0x96
    _dcmpl                = 151, // 0x97
    _dcmpg                = 152, // 0x98
    _ifeq                 = 153, // 0x99
    _ifne                 = 154, // 0x9a
    _iflt                 = 155, // 0x9b
    _ifge                 = 156, // 0x9c
    _ifgt                 = 157, // 0x9d
    _ifle                 = 158, // 0x9e
    _if_icmpeq            = 159, // 0x9f
    _if_icmpne            = 160, // 0xa0
    _if_icmplt            = 161, // 0xa1
    _if_icmpge            = 162, // 0xa2
    _if_icmpgt            = 163, // 0xa3
    _if_icmple            = 164, // 0xa4
    _if_acmpeq            = 165, // 0xa5
    _if_acmpne            = 166, // 0xa6
    _goto                 = 167, // 0xa7
    _jsr                  = 168, // 0xa8
    _ret                  = 169, // 0xa9
    _tableswitch          = 170, // 0xaa
    _lookupswitch         = 171, // 0xab
    _ireturn              = 172, // 0xac
    _lreturn              = 173, // 0xad
    _freturn              = 174, // 0xae
    _dreturn              = 175, // 0xaf
    _areturn              = 176, // 0xb0
    _return               = 177, // 0xb1
    _getstatic            = 178, // 0xb2
    _putstatic            = 179, // 0xb3
    _getfield             = 180, // 0xb4
    _putfield             = 181, // 0xb5
    _invokevirtual        = 182, // 0xb6
    _invokespecial        = 183, // 0xb7
    _invokestatic         = 184, // 0xb8
    _invokeinterface      = 185, // 0xb9
    _invokedynamic        = 186, // 0xba     // if EnableInvokeDynamic
    _new                  = 187, // 0xbb
    _newarray             = 188, // 0xbc
    _anewarray            = 189, // 0xbd
    _arraylength          = 190, // 0xbe
    _athrow               = 191, // 0xbf
    _checkcast            = 192, // 0xc0
    _instanceof           = 193, // 0xc1
    _monitorenter         = 194, // 0xc2
    _monitorexit          = 195, // 0xc3
    _wide                 = 196, // 0xc4
    _multianewarray       = 197, // 0xc5
    _ifnull               = 198, // 0xc6
    _ifnonnull            = 199, // 0xc7
    _goto_w               = 200, // 0xc8
    _jsr_w                = 201, // 0xc9
    _breakpoint           = 202, // 0xca

    number_of_java_codes,

    // JVM bytecodes
    _fast_agetfield       = number_of_java_codes,
    _fast_bgetfield       ,
    _fast_cgetfield       ,
    _fast_dgetfield       ,
    _fast_fgetfield       ,
    _fast_igetfield       ,
    _fast_lgetfield       ,
    _fast_sgetfield       ,

    _fast_aputfield       ,
    _fast_bputfield       ,
    _fast_zputfield       ,
    _fast_cputfield       ,
    _fast_dputfield       ,
    _fast_fputfield       ,
    _fast_iputfield       ,
    _fast_lputfield       ,
    _fast_sputfield       ,

    _fast_aload_0         ,
    _fast_iaccess_0       ,
    _fast_aaccess_0       ,
    _fast_faccess_0       ,

    _fast_iload           ,
    _fast_iload2          ,
    _fast_icaload         ,

    _fast_invokevfinal    ,
    _fast_linearswitch    ,
    _fast_binaryswitch    ,

    // special handling of oop constants:
    _fast_aldc            ,
    _fast_aldc_w          ,

    _return_register_finalizer    ,

    _shouldnotreachhere,      // For debugging

    // Platform specific JVM bytecodes
#ifdef TARGET_ARCH_x86
# include "bytecodes_x86.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "bytecodes_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "bytecodes_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "bytecodes_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "bytecodes_ppc.hpp"
#endif


    number_of_codes
  };
将操作栈中的栈顶元素弹出并设值本地变量表对应的变量。
astore
String s = "greet";
       0: ldc           #2                  // String greet
       2: astore_1
 
astore_
指令_astore,_astore_0,_astore_1,_astore_2,_astore_3
 
dstore
dstore_
 
fstore
fstore_
 
istore
istore_
 
lstore
lstore_
 
int i = 10;
long l = 100L;
float f = 0.1F;
double d = 0.1;
String s = "abc";
char c = 'a';
        0: bipush        10
       2: istore_1
       3: ldc2_w        #2                  // long 100l
       6: lstore_2
       7: ldc           #4                  // float 0.1f
       9: fstore        4
      11: ldc2_w        #5                  // double 0.1d
      14: dstore        5
      16: ldc           #7                  // String abc
      18: astore        7
      20: bipush        97
      22: istore        8
 
 
aastore
 
bastore
 
castore
 
dastore
 
fastore
 
iastore
 
lastore
 
sastore
 
将本地变量表中对应的变量压入到操作栈中。
aload
String s = "greet";
       0: ldc           #2                  // String greet
       2: astore_1
String s2 = s;
       3: aload_1
       4: astore_2
 
aload_
指令_aload_0,_aload_1,_aload_2,_aload_3,_fast_aload_0
 
dload
dload_
 
fload
fload_
 
iload
iload_
 
lload
lload_
 
aaload
 
baload
 
caload
 
daload
 
faload
 
iaload
 
laload
 
saload
int i2 = i;
long l2 = l;
float f2 = f;
double d2 = d;
String s2 = s;
char c2 = c;
 
      24: iload_1
      25: istore        9
      27: lload_2
      28: lstore        10
      30: fload         4
      32: fstore        12
      34: dload         5
      36: dstore        13
      38: aload         7
      40: astore        15
      42: iload         8
      44: istore        16
 
putfield
假设对象实例i有个字段value,对value赋值如下:
private int value;
value = 1;
       0: aload_0
       1: iconst_1
       2: putfield      #2                  // Field value:I
 
getfield
假设对象实例i有个字段value,对value赋值如下:
private int value;
value++;
       0: aload_0
       1: dup
       2: getfield      #2                  // Field value:I
       5: iconst_1
       6: iadd
       7: putfield      #2                  // Field value:I
int value2 = value;
       0: aload_0
       1: getfield      #2                  // Field value:I
       4: istore_1
 
putstatic
getstatic
 
 
new
格式:new  indexbyte1  indexbyte2
在Heap上为指定的类对象先分配一块内存,并初始化其中的变量为默认的初始值,最后将该对象的一个引用objectref压入操作栈的栈顶。
这里的类由 new字节码随后的 indexbyte1,indexbyte2两个参数决:(indexbyte1 << 8) | indexbyte2,其值表示要实例化的类在常量池中的索引
创建对象new例子:
public class JavaNew {

	public static void main(String[] args) {
		Object obj = new Object();
	}
}
反汇编结果:
>javap -c JavaNew
Compiled from "JavaNew.java"
public class JavaNew {
  public JavaNew();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":
()V
       4: return
 
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/Object
       3: dup
       4: invokespecial #1                  // Method java/lang/Object."":
()V
       7: astore_1
       8: return
}
从反编译的结果看,生成了一个构造方法,源代码中我没有为JavaNew定义任何构造方法,如果没有显式定义构造方法,Java会隐式定义一个默认的无参构造方法。在public JavaNew();下面是这个构造方法的字节码实现指令,其中一条重要的指令:invokespecial #1,在JVM解释执行遇到这个指令的时候,JVM会调用一个特殊方法:,这从后面的注释也可以看出来:// Method java/lang/Object."":()V,它对应Java层面的构造方法:public JavaNew() {},在这里我们可以认为构造方法也是一个特殊的构造方法,特殊在于在Java层面上它的方法名在Java层面看和类型一样,但在JVM层面却对应的是:,另外没有显式的返回类型,只有参数类型是一样的。最后要注意的事后面的()V,它是构造方法的签名,其形式如下:
(参数类型签名列表)返回类型签名
在另一篇文章: https://lobin.iteye.com/blog/2437928,讲GetMethodID函数的时候也会传入对应方法的签名。
创建数组newarray例子:
newarray
public class JavaNewArray {

	public static void main(String[] args) {
		int test[] = new int[123];
	}
}
 反汇编结果:
>javap -c JavaNewArray
Compiled from "JavaNewArray.java"
public class JavaNewArray {
  public JavaNewArray();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":
()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        123
       2: newarray       int
       4: astore_1
       5: return
}
dup
拷贝操作栈顶元素(值),并将拷贝的值压入到操作栈成为新的栈顶。
 
 
调用指令
invokedynamic
Java7开始支持 invokedynamic指令。
public class MainKlass5 {
    public static void main(String[] args) {
        Runnable x = () -> {
            System.out.println("greet!");
        };
        x.run();
        new Thread(x).start();
    }
}
     public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
       5: astore_1
       6: aload_1
       7: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
      12: new           #4                  // class java/lang/Thread
      15: dup
      16: aload_1
      17: invokespecial #5                  // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
      20: invokevirtual #6                  // Method java/lang/Thread.start:()V
      23: return
 
invokeinterface
 
public class MainKlass5 {
    public static void main(String[] args) {
        Runnable x = () -> {
            System.out.println("greet!");
        };
        x.run();
        new Thread(x).start();
    }
}
     
重点是 7: invokeinterface #3,  1这一行。
  public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
       5: astore_1
       6: aload_1
       7: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
      12: new           #4                  // class java/lang/Thread
      15: dup
      16: aload_1
      17: invokespecial #5                  // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
      20: invokevirtual #6                  // Method java/lang/Thread.start:()V
      23: return
 
invokespecial
特殊调用。 special理解为“特殊”其实并不准确,应该理解为“特定”,表示特定方法的调用,它其实是相对于“多态”的。
多态是运行时根据引用的对象实例,动态调用特定对象实例的对应方法。这种情况是invokevirtual。
而这里的 “特定”并不需要运行时动态决定调用特定对象 实例的对应方法,它是在编译时就已经决定了调用了哪一个方法。
隐式构造:
public class Klass0 {
}
  public asm.invokespecial.Klass0();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
显式构造
public class Klass1 {

    public Klass1() {

    }

    public Klass1(int i) {
        int i2 = i;
    }
}
  public asm.invokespecial.Klass1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
 
  public asm.invokespecial.Klass1(int);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: iload_1
       5: istore_2
       6: return
显式调用父类构造
public class SuperKlass1 extends Klass1 {

    public SuperKlass1(int i) {
        super(i);
    }
}
  public asm.invokespecial.SuperKlass1(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokespecial #2                  // Method asm/invokespecial/Klass1."":(I)V
       5: return
调用父类方法:
public class SuperKlass2 extends Klass2 {

    public void test0() {
        super.test0();
    }
}
  public void test0();
    Code:
       0: aload_0
       1: invokespecial #2                  // Method asm/invokespecial/Klass2.test0:()V
       4: return
构造(创建对象实例)
public class MainKlass1 {

    public static void main(String[] args) {
        SuperKlass1 klass0 = new Klass1(1);
        Klass1 klass1 = new Klass1(1);
    }
}
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class asm/invokespecial/Klass1
       3: dup
       4: iconst_1
       5: invokespecial #3                  // Method asm/invokespecial/Klass1."":(I)V
       8: astore_1
       9: new           #2                  // class asm/invokespecial/Klass1
      12: dup
      13: iconst_1
      14: invokespecial #3                  // Method asm/invokespecial/Klass1."":(I)V
      17: astore_2
      18: return
 
私有方法调用:
public class Klass3 {

    private void test0() {

    }

    public void test1() {
        test0();
    }
}
  public void test1();
    Code:
       0: aload_0
       1: invokespecial #2                  // Method test0:()V
       4: return
 
 
invokestatic
 
invokevirtual
public class MainKlass4 {

    public static void main(String[] args) {
        SuperKlass4 klass4 = new Klass4_1();
        klass4.test();

        klass4 = new Klass4_2();
        klass4.test();
    }
}
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class asm/invokespecial/Klass4_1
       3: dup
       4: invokespecial #3                  // Method asm/invokespecial/Klass4_1."":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method asm/invokespecial/SuperKlass4.test:()V
      12: new           #5                  // class asm/invokespecial/Klass4_2
      15: dup
      16: invokespecial #6                  // Method asm/invokespecial/Klass4_2."":()V
      19: astore_1
      20: aload_1
      21: invokevirtual #4                  // Method asm/invokespecial/SuperKlass4.test:()V
      24: return
 
ldc指令
将运行时常量池中的item压入到操作栈。
String str = "string abc";
        0: ldc           #2                  // String string abc
       2: astore_1
 
String str = new String("string abc");
 
       0: new           #2                  // class java/lang/String
       3: dup
       4: ldc           #3                  // String string abc
       6: invokespecial #4                  // Method java/lang/String."":(Ljava/lang/String;)V
       9: astore_1
在这个例子中,将字符串"string abc"压入到操作栈。
 
iconst_指令
将int常量i压入操作栈。如iconst_m1 = 2 (0x2), iconst_0 = 3 (0x3), iconst_1 = 4 (0x4), iconst_2 = 5 (0x5), iconst_3 = 6 (0x6), iconst_4 = 7 (0x7), iconst_5 = 8 (0x8)分别表示将-1, 0, 1, 2, 3, 4, 5压入操作栈。
       5: iconst_1
 
类加载时,在验证阶段针对指令的类型检查,参考 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.9,其中列举了所有在验证阶段会进行针对指令的类型检查。aaload、aastore、aconst_null、aload, aload_、anewarray、areturn、arraylength、astore, astore_、athrow等.
其他指令码
下面的这些指令并不在java中定义:
LoadLoad
StoreStore
LoadStore
StoreLoad
 
EnterLoad
EnterStore
ExitLoad
ExitStore
LoadEnter
LoadExit
StoreEnter
StoreExit
 
EnterEnter
ExitExit
EnterExit
ExitEnter
 
synchronized
public class SynchronizedTest {

    private int value;

    public synchronized void set(int value) {
        this.value = value;
    }

    public void set0(int value) {
        synchronized (this) {
            this.value = value;
        }
    }
}
 
public class instruction.SynchronizedTest {
  public instruction.SynchronizedTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
 
  public synchronized void set(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #2                  // Field value:I
       5: return
 
  public void set0(int);
    Code:
       0: aload_0
       1: dup
       2: astore_2
       3: monitorenter
       4: aload_0
       5: iload_1
       6: putfield      #2                  // Field value:I
       9: aload_2
      10: monitorexit
      11: goto          19
      14: astore_3
      15: aload_2
      16: monitorexit
      17: aload_3
      18: athrow
      19: return
    Exception table:
       from    to  target type
           4    11    14   any
          14    17    14   any
}
从反编译的字节码结果看, synchronized以修饰符作用在方法上,在字节码上是不体现的。但在方法内部作为同步原语使用的话,在字节码上体现在 monitorenter/ monitorexit上。
赋值
private int value;

public void set() {
    value = 100;
}
       0: aload_0
     1: bipush        100
     3: putfield      #2                  // Field value:I
     6: return
volatile变量的赋值:
private volatile int j;

public void test_assign() {
    j = 11;
}
       0: aload_0
       1: bipush        11
       3: putfield      #2                  // Field j:I
       6: return
volatile的作用并没有体现在反编译的字节码上。这个需要在反编译到汇编才能看得到效果:
  0x00c69fbd: mov    $0xb,%esi
  0x00c69fc2: mov    %esi,0x8(%eax)
  0x00c69fc5: lock addl $0x0,(%esp)     ;*putfield j
                                        ; - ins.VolatileTest::test_assign@3 (line 11)
                                        ; - ins.VolatileTest::main@9 (line 16)
lock addl $0x0,(%esp)实际上就是个内存屏障,它能保证变量的可见性。至于volatile的禁止重排序作用,这里还看不到效果。
关于 lock指令,x86下是这么描述的:
来自https://www.felixcloutier.com/x86/lock的资料:
LOCK — Assert LOCK# Signal Prefix 写道
Description

Causes the processor’s LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal ensures that the processor has exclusive use of any shared memory while the signal is asserted.

In most IA-32 and all Intel 64 processors, locking may occur without the LOCK# signal being asserted. See the “IA-32 Architecture Compatibility” section below for more details.

The LOCK prefix can be prepended only to the following instructions and only to those forms of the instructions where the destination operand is a memory operand: ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG. If the LOCK prefix is used with one of these instructions and the source operand is a memory operand, an undefined opcode exception (#UD) may be generated. An undefined opcode exception will also be generated if the LOCK prefix is used with any instruction not in the above list. The XCHG instruction always asserts the LOCK# signal regardless of the presence or absence of the LOCK prefix.

The LOCK prefix is typically used with the BTS instruction to perform a read-modify-write operation on a memory location in shared memory environment.

The integrity of the LOCK prefix is not affected by the alignment of the memory field. Memory locking is observed for arbitrarily misaligned fields.

This instruction’s operation is the same in non-64-bit modes and 64-bit mode.
 
 
而如果没有volatile修饰,反编译的汇编效果类似:
  0x00c69fbd: movl   $0xa,0x8(%eax)     ;*putfield i
                                        ; - ins.NonvolatileTest::test_assign@3 (line 15)
                                        ; - ins.NonvolatileTest::main@9 (line 22)
 
如果是本地变量的赋值:
public void assign() {
    int i = 100;
}
      0: bipush        100
     2: istore_1
     3: return
 
i++操作:
public class VariableSetTest {

    private int value;

    public static void main(String[] args) {
        VariableSetTest test = new VariableSetTest();


        test.value++;
        System.out.println(test.value);
    }
}
 public class VariableSetTest {
  public VariableSetTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
 
  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class VariableSetTest
       3: dup
       4: invokespecial #3                  // Method "":()V
       7: astore_1
       8: aload_1
       9: dup
      10: getfield      #4                  // Field value:I
      13: iconst_1
      14: iadd
      15: putfield      #4                  // Field value:I
      18: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      21: aload_1
      22: getfield      #4                  // Field value:I
      25: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
      28: return
}
局部变量的i++操作:
public class VariableSetTest2 {

    public static void main(String[] args) {
        int value = 0;
        value++;
        System.out.println(value);
    }
}
 public class VariableSetTest2 {
  public VariableSetTest2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
 
  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iinc          1, 1
       5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: iload_1
       9: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      12: return
}
1、VariableSetTest中的++操作对应的指令为14: iadd,但 VariableSetTest2中的++操作对应的指令为 2: iinc          1, 1。
2、 VariableSetTest, VariableSetTest2中的++操作会更新value的值,但在反编译后的指令码中没有astore类似的指令更新本地变量表中对应变量value的值。

 

 

你可能感兴趣的:(JVM 指令)