0%

class字节码

  • load 读取数据到操作栈
  • add 相加 出栈比较的2个元素,入栈结果
  • store 存储到变量表
  • const_ 读取数据

  • return 返回

  • bipush x 将x压栈

  • sub 减法 出栈比较的2个元素,入栈结果

  • mul 乘法 出栈比较的2个元素,入栈结果

  • i2f int转float 出栈栈顶,入栈结果

  • getstatic 获取静态值

  • putstatic 设置静态

  • ldc 将字符串推至栈顶

  • putfield 赋值 栈顶元素出栈的数据保存到再次出栈的栈顶元素中 (2次出栈)

  • getfield 获取栈顶元素的变量,然后将栈顶元素出栈,新的元素变量入栈 (1次出栈,1次入栈)

  • _new 分配空间,地址压栈

  • dup 复制栈顶元素,再次入栈,此时栈顶中有2个重复元素

  • invokespecial 需要弹出dup复制的栈顶元素

  • ifnonnull l0 不为空,跳转到l0

  • _goto l1 跳转到l1

  • 比较 出栈比较的2个元素

    • if_icmpne 不等于
    • if_icmple 小于
    • if_icmplt 小于等于
    • if_icmpge 大于
    • if_icmpgt 大于等于
    • if_icmpeq 等于
  • iinc

    • iinc 2,100 位置2slot的值加100
    • iinc 2,-100
  • int 入栈

    • 当 int 取值 -1~5 时,JVM 采用 iconst 指令将常量压入栈中。
    • 当 int 取值 -128~127 时,JVM 采用 bipush 指令将常量压入栈中。
    • 当 int 取值 -32768~32767 时,JVM 采用 sipush 指令将常量压入栈中。
    • 当 int 取值 -2147483648~2147483647 时,JVM 采用 ldc 指令将常量压入栈中。

重点:区分哪些指令是入栈,哪些指令是出栈

分析

  • 构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // 源码
    public class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
    this.name = name;
    this.age = age;
    }

    public void doAction() {

    }
    }
    // groovified (字节码)

    public class org/example/Person {


    // access flags 0x1
    public Ljava/lang/String; name

    // access flags 0x1
    public I age

    @groovyx.ast.bytecode.Bytecode
    public void <init>(String a,int b) {
    aload 0 // 入栈 this
    invokespecial 'java/lang/Object.<init>','()V' // 调用this的父类init并出栈
    aload 0 //入栈 this
    aload 1 // 入栈 a
    putfield 'org/example/Person.name','Ljava/lang/String;' // 出栈this和a,将a赋值给this.name
    aload 0 //入栈 this
    iload 2 // 入栈 b
    putfield 'org/example/Person.age','I' // 出栈this和b //将b赋值给this.age
    return
    }

    @groovyx.ast.bytecode.Bytecode
    public void doAction() {
    return
    }
    }
  • new

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 源码
    public void method(Person person) {
    new Person("songpengfei", 30);
    }
    // groovified
    @groovyx.ast.bytecode.Bytecode
    public void method(org.example.Person a) {
    _new 'org/example/Person' // 初始化Person,并入栈
    dup // 复制栈顶Person并入栈
    ldc "songpengfei" // 入栈 字符串
    bipush 30 // 入栈 30
    invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V' //出战 Person,字符串,30,并执行Person构造方法
    pop // invokespecial出栈了1次Person,还剩余1个Person,pop出栈Person
    return
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//源码
public void method(Person person) {
Person songpengfei = new Person("songpengfei", 30);
songpengfei.doAction();
}
// groovified
public void method(org.example.Person a) {
_new 'org/example/Person'
dup
ldc "songpengfei"
bipush 30
invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
astore 2 // 这里栈顶还有一个Person,将person出栈,并存储到2
aload 2 // 2号slot是刚入栈的Person,将Person再次入栈
invokevirtual 'org/example/Person.doAction','()V' // 将2号出栈并执行person的doAction方法
return
}

invokevirtual 如果有返回值,返回值会入栈,如果没有返回值不会入栈

  • try-finally

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public void method(Person person) {
    try {
    Person songpengfei = new Person("songpengfei", 30);
    songpengfei.doAction();
    } finally {
    int a = 100;
    }
    }



    public void method(org.example.Person a) {
    trycatchblock l0,l1,l2,null
    l0
    _new 'org/example/Person'
    dup
    ldc "songpengfei"
    bipush 30
    invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
    astore 2
    aload 2
    invokevirtual 'org/example/Person.doAction','()V'
    l1
    bipush 100
    istore 2
    _goto l3
    l2 // 异常情况
    astore 3 // 将异常出栈,存入slot 3
    bipush 100 // 入栈 100
    istore 4 // 出栈存到 slot 4
    aload 3 // 入栈异常
    athrow //抛出异常
    l3
    return
    }
  • try-catch

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
       public void method(Person person) {
    try {
    Person songpengfei = new Person("songpengfei", 30);
    songpengfei.doAction();
    } catch (Exception e) {
    int c = 20;
    }
    }


    public void method(org.example.Person a) {
    trycatchblock l0,l1,l2,'java/lang/Exception'
    l0
    _new 'org/example/Person'
    dup
    ldc "songpengfei"
    bipush 30
    invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
    astore 2
    aload 2
    invokevirtual 'org/example/Person.doAction','()V'
    l1
    _goto l3
    l2
    astore 2
    bipush 20
    istore 3
    l3
    return
    }
  • try-catch-finally

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    //源码
    public void method(Person person) {
    try {
    Person songpengfei = new Person("songpengfei", 30);
    songpengfei.doAction();
    } catch (Exception e) {
    int c = 100;
    } finally {
    int a = 20;
    }
    }

    // groovified
    public void method(org.example.Person a) {
    trycatchblock l0,l1,l2,'java/lang/Exception'
    trycatchblock l0,l1,l3,null
    trycatchblock l2,l4,l3,null
    trycatchblock l3,l5,l3,null
    l0 // try 块
    _new 'org/example/Person'
    dup
    ldc "songpengfei"
    bipush 30
    invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V'
    astore 2
    aload 2
    invokevirtual 'org/example/Person.doAction','()V'

    l1 //finally块
    bipush 20
    istore 2
    _goto l6

    l2 // catch块
    astore 2
    bipush 100
    istore 3

    l4 // finally块
    bipush 20
    istore 2
    _goto l6

    l3
    astore 4

    l5 // finally块 athrow
    bipush 20
    istore 5
    aload 4
    athrow

    l6
    return
    }
    }
  • synchronized

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    //  源码
    public class Main {

    private final Object lock = new Object();
    public static void main(String[] args) {
    }

    public void method(Person person) {
    synchronized (lock) {
    Person songpengfei = new Person("songpengfei", 30);
    songpengfei.doAction();
    }
    }
    }
    // groovified

    // class version 52.0 (52)
    // access flags 0x21
    public class org/example/Main {


    // access flags 0x12
    private final Ljava/lang/Object; lock

    @groovyx.ast.bytecode.Bytecode
    public void <init>() {
    aload 0 // this 入栈
    invokespecial 'java/lang/Object.<init>','()V' // this出栈,并执行Object构造
    aload 0 // this入栈
    _new 'java/lang/Object' //执行lock对象的new 入栈
    dup // 执行赋值lock对象入栈
    invokespecial 'java/lang/Object.<init>','()V' // lock对象出栈,执行Object构造
    putfield 'org/example/Main.lock','Ljava/lang/Object;' // 出栈this和lock,将lock赋值
    return
    }

    @groovyx.ast.bytecode.Bytecode
    public static void main(String[] a) {
    return
    }

    @groovyx.ast.bytecode.Bytecode
    public void method(org.example.Person a) {
    trycatchblock l0,l1,l2,null
    trycatchblock l2,l3,l2,null
    aload 0 // this入栈
    getfield 'org/example/Main.lock','Ljava/lang/Object;' // 出栈this,入栈lock
    dup // 复制lock入栈
    astore 2 // 将lock存入到slot 2
    monitorenter // lock监控并出栈
    l0
    _new 'org/example/Person' //创建Person,并入栈
    dup // 复制Person 并入栈
    ldc "songpengfei" // 入栈字符串
    bipush 30 // 入栈整数30
    invokespecial 'org/example/Person.<init>','(Ljava/lang/String;I)V' // 出栈Person,字符串,30,并调用构造方法
    astore 3 //存储 Person并出栈
    aload 3 // 入栈 Person
    invokevirtual 'org/example/Person.doAction','()V' // 执行
    aload 2 // 入栈lock
    monitorexit // 出栈lock 退出监控
    l1 // finally
    _goto l4
    l2 //
    astore 4 // catch情况
    aload 2
    monitorexit
    l3
    aload 4
    athrow
    l4
    return
    }
    }
  • 匿名内部类 (解析)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    // 源码
    public void method(final int a) {
    final int c = 30;
    Request request = new Request();
    request.request(new Request.Callback() {
    @Override
    public void callback() {
    int b = a + c; // 反编译之后c直接copy为30;
    int d = b + 1;
    }
    });
    }


    // access flags 0x0
    INNERCLASS org/example/Main$1 null null
    // access flags 0x609
    public static abstract INNERCLASS org/example/Request$Callback org/example/Request Callback


    // groovified
    public void method(int a) {
    bipush 30
    istore 2
    _new 'org/example/Request'
    dup
    invokespecial 'org/example/Request.<init>','()V'
    astore 3
    aload 3
    _new 'org/example/Main$1'
    dup
    aload 0
    iload 1
    invokespecial 'org/example/Main$1.<init>','(Lorg/example/Main;I)V'
    invokevirtual 'org/example/Request.request','(Lorg/example/Request$Callback;)V'
    return
    }





    内部类Callback

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    {
    final int val$a;
    descriptor: I
    flags: ACC_FINAL, ACC_SYNTHETIC

    final org.example.Main this$0;
    descriptor: Lorg/example/Main;
    flags: ACC_FINAL, ACC_SYNTHETIC

    org.example.Main$1(org.example.Main, int);
    descriptor: (Lorg/example/Main;I)V
    flags:
    Code:
    stack=2, locals=3, args_size=3
    0: aload_0
    1: aload_1
    2: putfield #1 // Field this$0:Lorg/example/Main;
    5: aload_0
    6: iload_2
    7: putfield #2 // Field val$a:I
    10: aload_0
    11: invokespecial #3 // Method java/lang/Object."<init>":()V
    14: return
    LineNumberTable:
    line 15: 0
    LocalVariableTable:
    Start Length Slot Name Signature
    0 15 0 this Lorg/example/Main$1;
    0 15 1 this$0 Lorg/example/Main;

    public void callback();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=2, locals=3, args_size=1
    0: aload_0
    1: getfield #2 // Field val$a:I
    4: bipush 30
    6: iadd
    7: istore_1
    8: iload_1
    9: iconst_1
    10: iadd
    11: istore_2
    12: return
    LineNumberTable:
    line 18: 0
    line 19: 8
    line 20: 12
    LocalVariableTable:
    Start Length Slot Name Signature
    0 13 0 this Lorg/example/Main$1;
    8 5 1 b I
    12 1 2 d I
    }

解析内部类需要使用反斜杠

1
javap -v org/example/Main\$1.class

性能问题

  1. static

    1
    2
    3
    4
    5
    6
    7
    // 1
    public static final int A = 5;
    // 2
    public static final int A;
    static {
    A = 5;
    }

    上面两种静态变量的定义方式,1的性能要高于2

  2. a+=100 和 a=a+100

    1
    2
    3
    4
    5
    6
    7
    // a+=100      
    iinc 2,100
    // a=a+100
    iload 2
    bipush 100
    iadd
    istore 2

参考:https://blog.51cto.com/u_15639793/5297175