上级目录

概览

从 Instruction 的角度来说,与 stack 相关的 opcode 有 9 个,内容如下:

opcode mnemonic symbol opcode mnemonic symbol opcode mnemonic symbol
87 pop 90 dup_x1 93 dup2_x1
88 pop2 91 dup_x2 94 dup2_x2
89 dup 92 dup2 95 swap

从 ASM 的角度来说,这些 opcode 与 MethodVisitor.visitXxxInsn() 方法对应关系如下:

  • MethodVisitor.visitInsn():
    • pop, pop2
    • dup, dup_x1, dup_x2
    • dup2, dup2_x1, dup2_x2
    • swap

pop

pop

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public void test() {
        Math.max(3, 4);
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: iconst_3
       1: iconst_4
       2: invokestatic  #2                  // Method java/lang/Math.max:(II)I
       5: pop
       6: return
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_3);
methodVisitor.visitInsn(ICONST_4);
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(II)I", false);
methodVisitor.visitInsn(POP);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: iconst_3                 // {this} | {int}
0001: iconst_4                 // {this} | {int, int}
0002: invokestatic    #2       // {this} | {int}
0005: pop                      // {this} | {}
0006: return                   // {} | {}

从 JVM 规范的角度来看,pop 指令对应的 Operand Stack 的变化如下:

..., value →

...

Pop the top value from the operand stack. The pop instruction must not be used unless value is a value of a category 1 computational type.

pop2

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public void test() {
        Math.max(3L, 4L);
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: ldc2_w        #2                  // long 3l
       3: ldc2_w        #4                  // long 4l
       6: invokestatic  #6                  // Method java/lang/Math.max:(JJ)J
       9: pop2
      10: return
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitLdcInsn(new Long(3L));
methodVisitor.visitLdcInsn(new Long(4L));
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Math", "max", "(JJ)J", false);
methodVisitor.visitInsn(POP2);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(4, 1);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: ldc2_w          #2       // {this} | {long, top}
0003: ldc2_w          #4       // {this} | {long, top, long, top}
0006: invokestatic    #6       // {this} | {long, top}
0009: pop2                     // {this} | {}
0010: return                   // {} | {}

从 JVM 规范的角度来看,pop2 指令对应的 Operand Stack 的变化如下:

Form 1:

..., value2, value1 →

...

where each of value1 and value2 is a value of a category 1 computational type.

Form 2:

..., value →

...

where value is a value of a category 2 computational type.

dup

dup

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public void test() {
        int a;
        int b;
        b = a = 2;
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: iconst_2
       1: dup
       2: istore_1
       3: istore_2
       4: return
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitInsn(ICONST_2);
methodVisitor.visitInsn(DUP);
methodVisitor.visitVarInsn(ISTORE, 1);
methodVisitor.visitVarInsn(ISTORE, 2);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 3);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: iconst_2                 // {this} | {int}
0001: dup                      // {this} | {int, int}
0002: istore_1                 // {this, int} | {int}
0003: istore_2                 // {this, int, int} | {}
0004: return                   // {} | {}

从 JVM 规范的角度来看,dup 指令对应的 Operand Stack 的变化如下:

..., value →

..., value, value

Duplicate the top value on the operand stack and push the duplicated value onto the operand stack.

The dup instruction must not be used unless value is a value of a category 1 computational type.

dup_x1

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    private int num = 0;

    public static int test(HelloWorld instance, int val) {
        return instance.num = val;
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
  private int num;
...

  public static int test(sample.HelloWorld, int);
    Code:
       0: aload_0
       1: iload_1
       2: dup_x1
       3: putfield      #2                  // Field num:I
       6: ireturn
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitInsn(DUP_X1);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/HelloWorld", "num", "I");
methodVisitor.visitInsn(IRETURN);
methodVisitor.visitMaxs(3, 2);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {HelloWorld, int} | {}
0000: aload_0                  // {HelloWorld, int} | {HelloWorld}
0001: iload_1                  // {HelloWorld, int} | {HelloWorld, int}
0002: dup_x1                   // {HelloWorld, int} | {int, HelloWorld, int}
0003: putfield        #2       // {HelloWorld, int} | {int}
0006: ireturn                  // {} | {}

从 JVM 规范的角度来看,dup_x1 指令对应的 Operand Stack 的变化如下:

..., value2, value1 →

..., value1, value2, value1

Duplicate the top value on the operand stack and insert the duplicated value two values down in the operand stack.

The dup_x1 instruction must not be used unless both value1 and value2 are values of a category 1 computational type.

dup_x2

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public static int test(int[] array, int i, int value) {
        return array[i] = value;
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public static int test(int[], int, int);
    Code:
       0: aload_0
       1: iload_1
       2: iload_2
       3: dup_x2
       4: iastore
       5: ireturn
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitVarInsn(ILOAD, 2);
methodVisitor.visitInsn(DUP_X2);
methodVisitor.visitInsn(IASTORE);
methodVisitor.visitInsn(IRETURN);
methodVisitor.visitMaxs(4, 3);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {[I, int, int} | {}
0000: aload_0                  // {[I, int, int} | {[I}
0001: iload_1                  // {[I, int, int} | {[I, int}
0002: iload_2                  // {[I, int, int} | {[I, int, int}
0003: dup_x2                   // {[I, int, int} | {int, [I, int, int}
0004: iastore                  // {[I, int, int} | {int}
0005: ireturn                  // {} | {}

从 JVM 规范的角度来看,dup_x2 指令对应的 Operand Stack 的变化如下:

Form 1:

..., value3, value2, value1 →

..., value1, value3, value2, value1

where value1, value2, and value3 are all values of a category 1 computational type.

Form 2:

..., value2, value1 →

..., value1, value2, value1

where value1 is a value of a category 1 computational type and value2 is a value of a category 2 computational type.

dup2

dup2

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public void test() {
        long a;
        long b;
        b = a = 2;
    }
}
public class HelloWorld {
    public void test() {
        int[] array = new int[5];
        array[0]++; // 这里会生成 dup2 指令
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: ldc2_w        #2                  // long 2l
       3: dup2
       4: lstore_1
       5: lstore_3
       6: return
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitLdcInsn(new Long(2L));
methodVisitor.visitInsn(DUP2);
methodVisitor.visitVarInsn(LSTORE, 1);
methodVisitor.visitVarInsn(LSTORE, 3);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(4, 5);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: ldc2_w          #2       // {this} | {long, top}
0003: dup2                     // {this} | {long, top, long, top}
0004: lstore_1                 // {this, long, top} | {long, top}
0005: lstore_3                 // {this, long, top, long, top} | {}
0006: return                   // {} | {}

从 JVM 规范的角度来看,dup2 指令对应的 Operand Stack 的变化如下:

Form 1:

..., value2, value1 →

..., value2, value1, value2, value1

where both value1 and value2 are values of a category 1 computational type.

Form 2:

..., value →

..., value, value

where value is a value of a category 2 computational type.

dup2_x1

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    private long num = 0;

    public static long test(HelloWorld instance, long val) {
        return instance.num = val;
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
  private long num;
...

  public static long test(sample.HelloWorld, long);
    Code:
       0: aload_0
       1: lload_1
       2: dup2_x1
       3: putfield      #2                  // Field num:J
       6: lreturn
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(LLOAD, 1);
methodVisitor.visitInsn(DUP2_X1);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/HelloWorld", "num", "J");
methodVisitor.visitInsn(LRETURN);
methodVisitor.visitMaxs(5, 3);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {HelloWorld, long, top} | {}
0000: aload_0                  // {HelloWorld, long, top} | {HelloWorld}
0001: lload_1                  // {HelloWorld, long, top} | {HelloWorld, long, top}
0002: dup2_x1                  // {HelloWorld, long, top} | {long, top, HelloWorld, long, top}
0003: putfield        #2       // {HelloWorld, long, top} | {long, top}
0006: lreturn                  // {} | {}

从 JVM 规范的角度来看,dup2_x1 指令对应的 Operand Stack 的变化如下:

Form 1:

..., value3, value2, value1 →

..., value2, value1, value3, value2, value1

where value1, value2, and value3 are all values of a category 1 computational type.

Form 2:

..., value2, value1 →

..., value1, value2, value1

where value1 is a value of a category 2 computational type and value2 is a value of a category 1 computational type.

dup2_x2

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public static long test(long[] array, int i, long value) {
        return array[i] = value;
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public static long test(long[], int, long);
    Code:
       0: aload_0
       1: iload_1
       2: lload_2
       3: dup2_x2
       4: lastore
       5: lreturn
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ILOAD, 1);
methodVisitor.visitVarInsn(LLOAD, 2);
methodVisitor.visitInsn(DUP2_X2);
methodVisitor.visitInsn(LASTORE);
methodVisitor.visitInsn(LRETURN);
methodVisitor.visitMaxs(6, 4);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {[J, int, long, top} | {}
0000: aload_0                  // {[J, int, long, top} | {[J}
0001: iload_1                  // {[J, int, long, top} | {[J, int}
0002: lload_2                  // {[J, int, long, top} | {[J, int, long, top}
0003: dup2_x2                  // {[J, int, long, top} | {long, top, [J, int, long, top}
0004: lastore                  // {[J, int, long, top} | {long, top}
0005: lreturn                  // {} | {}

从 JVM 规范的角度来看,dup2_x2 指令对应的 Operand Stack 的变化如下:

Form 1:

..., value4, value3, value2, value1 →

..., value2, value1, value4, value3, value2, value1

where value1, value2, value3, and value4 are all values of a category 1 computational type.

Form 2:

..., value3, value2, value1 →

..., value1, value3, value2, value1

where value1 is a value of a category 2 computational type and value2 and value3 are both values of a category 1 computational type.

Form 3:

..., value3, value2, value1 →

..., value2, value1, value3, value2, value1

where value1 and value2 are both values of a category 1 computational type and value3 is a value of a category 2 computational type.

Form 4:

..., value2, value1 →

..., value1, value2, value1

where value1 and value2 are both values of a category 2 computational type.

swap

从 Java 语言的视角,有一个 HelloWorld 类,代码如下:

public class HelloWorld {
    public void test() {
        System.out.println("Hello ASM");
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String Hello ASM
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

从 ASM 的视角来看,方法体对应的内容如下:

methodVisitor.visitCode();
methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
methodVisitor.visitLdcInsn("Hello ASM");
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(2, 1);
methodVisitor.visitEnd();

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: getstatic       #2       // {this} | {PrintStream}
0003: ldc             #3       // {this} | {PrintStream, String}
0005: invokevirtual   #4       // {this} | {}
0008: return                   // {} | {}

为了使用 swap 指令,我们编写如下 ASM 代码:

import lsieun.utils.FileUtils;
import org.objectweb.asm.*;

import static org.objectweb.asm.Opcodes.*;

public class HelloWorldGenerateCore {
    public static void main(String[] args) throws Exception {
        String relative_path = "sample/HelloWorld.class";
        String filepath = FileUtils.getFilePath(relative_path);

        // (1) 生成 byte[]内容
        byte[] bytes = dump();

        // (2) 保存 byte[]到文件
        FileUtils.writeBytes(filepath, bytes);
    }

    public static byte[] dump() throws Exception {
        // (1) 创建 ClassWriter 对象
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

        // (2) 调用 visitXxx()方法
        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld",
                null, "java/lang/Object", null);

        {
            MethodVisitor mv1 = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv1.visitCode();
            mv1.visitVarInsn(ALOAD, 0);
            mv1.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv1.visitInsn(RETURN);
            mv1.visitMaxs(1, 1);
            mv1.visitEnd();
        }

        {
            MethodVisitor mv2 = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
            mv2.visitCode();
            mv2.visitLdcInsn("Hello ASM");
            mv2.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv2.visitInsn(SWAP);
            mv2.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            mv2.visitInsn(RETURN);
            mv2.visitMaxs(2, 1);
            mv2.visitEnd();
        }
        cw.visitEnd();

        // (3) 调用 toByteArray()方法
        return cw.toByteArray();
    }
}

从 Instruction 的视角来看,方法体对应的内容如下:

$ javap -c -p sample.HelloWorld
public class sample.HelloWorld {
...
  public void test();
    Code:
       0: ldc           #11                 // String Hello ASM
       2: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       5: swap
       6: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       9: return
}

从 Frame 的视角来看,local variable 和 operand stack 的变化:

                               // {this} | {}
0000: ldc             #11      // {this} | {String}
0002: getstatic       #17      // {this} | {String, PrintStream}
0005: swap                     // {this} | {PrintStream, String}
0006: invokevirtual   #23      // {this} | {}
0009: return                   // {} | {}

从 JVM 规范的角度来看,swap 指令对应的 Operand Stack 的变化如下:

..., value2, value1 →

..., value1, value2

Swap the top two values on the operand stack.

The swap instruction must not be used unless value1 and value2 are both values of a category 1 computational type.