• Java 中有 goto 吗?


    goto 是 Java 中的关键字, 但还处于保留状态, 在实际的开发中并不能使用. 本文列举了 Java 中的关键字以及引入时间, 同时讨论了和 goto 效果类似的 break label 的语法以及使用的 demo. 最后从将 demo 进行了反编译并逐条分析了 Java 字节码的执行, 得出的结论是 break label 底层比较简单就是一行 goto xx 的字节码指令. 在分析字节码的过程中重温了一下 Java 基于栈实现的执行引擎运行.

    原文地址:Java 中有 goto 吗?

    欢迎访问我的博客: http://blog.duhbb.com/

    Java 关键字

    下表中列举了 Java 中的关键字, 这些关键字都不可以作为标识符. constgo 是保留关键字, 虽然没有正式使用, 但是你也不能把它们作为标识符. true, falsenull 虽然看上去像关键字, 但是它们实际上是 literals, 它们也不能作为标识符使用.

    abstract continue for new switch
    assert*** default goto* package synchronized
    boolean do if private this
    break double implements protected throw
    byte else import public throws
    case enum**** instanceof return transient
    catch extends int short try
    char final interface static void
    class finally long strictfp** volatile
    const* float native super while

    备注:

    • *: 未使用
    • **: 1.2 中引入
    • ***:1.4 中引入
    • ****:5.0 中引入

    以上来自:Java Language Keywords

    可见 Java 中确实有 goto, 但是是保留的关键字, 并不能实际使用.So, 我们不能 goto anywhere.

    break label 用法

    虽然 Java 中没有 C 语言中 goto 的那种用法, 但是有一个"类似"的.

    语法

    语法格式: break label, label 你可以自己定义, 只要不冲突就行.

    break 语句可以终止带标签的语句的执行; 它并不会将控制流转移到标签上, 而是将控制流立即转移到了带标签语句的下一条语句中.

    例子

    first:
      for( int i = 0; i < 10; i++) {
        second:
          for(int j = 0; j < 5; j ++ ) {
            break xxx;
          }
      }
    
    third:
      for( int a = 0; a < 10; a++) {
    
      }
    
    • xxx 只能是 first 或者 second, 而不能是 third, 也就是只能 break 包裹 break 的语句; break third 会报编译错误.
    • break first 会跳出最外层的 for 循环, 而 break second 则会跳出内层的 for 循环, 外层的 for 循环继续.

    查看字节码

    源代码:Main.java

    public class Main {
        public static void main(String[] args) {
            first:
            for (int i = 0; i < 10; i++) {
                second:
                for (int j = 0; j < 5; j++) {
                    System.out.println("i = " + i + ", j = " + j);
                    break first;
                }
            }
    
            third:
            for (int a = 0; a < 10; a++) {
                System.out.println(a);
            }
        }
    }
    

    javap -v Main.class 反编译后的字节:

    duhbb@debian:/mnt/data/IdeaProjects/test/target/classes$ javap -v Main.class 
    Classfile /mnt/data/IdeaProjects/test/target/classes/Main.class
      Last modified 2022-6-8; size 913 bytes
      MD5 checksum f56881b622c0cfceb531278564352491
      Compiled from "Main.java"
    public class Main
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #13.#32        // java/lang/Object."<init>":()V
       #2 = Fieldref           #33.#34        // java/lang/System.out:Ljava/io/PrintStream;
       #3 = Class              #35            // java/lang/StringBuilder
       #4 = Methodref          #3.#32         // java/lang/StringBuilder."<init>":()V
       #5 = String             #36            // i =
       #6 = Methodref          #3.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       #7 = Methodref          #3.#38         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
       #8 = String             #39            // , j =
       #9 = Methodref          #3.#40         // java/lang/StringBuilder.toString:()Ljava/lang/String;
      #10 = Methodref          #41.#42        // java/io/PrintStream.println:(Ljava/lang/String;)V
      #11 = Methodref          #41.#43        // java/io/PrintStream.println:(I)V
      #12 = Class              #44            // Main
      #13 = Class              #45            // java/lang/Object
      #14 = Utf8               <init>
      #15 = Utf8               ()V
      #16 = Utf8               Code
      #17 = Utf8               LineNumberTable
      #18 = Utf8               LocalVariableTable
      #19 = Utf8               this
      #20 = Utf8               LMain;
      #21 = Utf8               main
      #22 = Utf8               ([Ljava/lang/String;)V
      #23 = Utf8               j
      #24 = Utf8               I
      #25 = Utf8               i
      #26 = Utf8               a
      #27 = Utf8               args
      #28 = Utf8               [Ljava/lang/String;
      #29 = Utf8               StackMapTable
      #30 = Utf8               SourceFile
      #31 = Utf8               Main.java
      #32 = NameAndType        #14:#15        // "<init>":()V
      #33 = Class              #46            // java/lang/System
      #34 = NameAndType        #47:#48        // out:Ljava/io/PrintStream;
      #35 = Utf8               java/lang/StringBuilder
      #36 = Utf8               i =
      #37 = NameAndType        #49:#50        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      #38 = NameAndType        #49:#51        // append:(I)Ljava/lang/StringBuilder;
      #39 = Utf8               , j =
      #40 = NameAndType        #52:#53        // toString:()Ljava/lang/String;
      #41 = Class              #54            // java/io/PrintStream
      #42 = NameAndType        #55:#56        // println:(Ljava/lang/String;)V
      #43 = NameAndType        #55:#57        // println:(I)V
      #44 = Utf8               Main
      #45 = Utf8               java/lang/Object
      #46 = Utf8               java/lang/System
      #47 = Utf8               out
      #48 = Utf8               Ljava/io/PrintStream;
      #49 = Utf8               append
      #50 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
      #51 = Utf8               (I)Ljava/lang/StringBuilder;
      #52 = Utf8               toString
      #53 = Utf8               ()Ljava/lang/String;
      #54 = Utf8               java/io/PrintStream
      #55 = Utf8               println
      #56 = Utf8               (Ljava/lang/String;)V
      #57 = Utf8               (I)V
    {
      public Main();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 5: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   LMain;
    
      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=3, locals=3, args_size=1
             0: iconst_0                          // 将常数 0 压入操作数栈
             1: istore_1                          // 将操作数出栈, 并给到本地变量表的第 1 位置的变量, 也就是 i
             2: iload_1                           // 就是变量表中第 1 个位置的 i 压栈到操作数栈顶
             3: bipush        10                  // 把常量 10 压入到操作数栈中
             5: if_icmpge     58                  // 进行比较, 如果为 false 则跳到 58 行 (我猜的)
             8: iconst_0                          // 将常数 0 压入操作数栈
             9: istore_2                          // 将其弹给并给到本地变量表的第 1 位置的变量, 也就是 j
            10: iload_2                           // 就是变量表中第 2 个位置的 i 压栈到操作数栈顶
            11: iconst_5                          // 把常量 5 压入到操作数栈中
            12: if_icmpge     52                  // 进行一通比较, 如果为 false 则跳到 52 行执行
            15: getstatic     #2                  // 获取类的静态字段 Field java/lang/System.out:Ljava/io/PrintStream;
            18: new           #3                  // 创建一个对象, 对象是通过字节索引在常量池中定位的 class java/lang/StringBuilder
            21: dup                               // 复制在栈顶的值
            22: invokespecial #4                  // 调用 StringBuilder 的方法进行初始化 Method java/lang/StringBuilder."<init>":()V
            25: ldc           #5                  // 字符串入栈 String i =
            27: invokevirtual #6                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            30: iload_1                           // 就是变量表中第 1 个位置的 i 压栈到操作数栈顶 这里就是 i 了, 因为准备把 i 拼接到后面去
            31: invokevirtual #7                  // 调用 StringBuilder 的 append Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
            34: ldc           #8                  // 字符串入栈 String , j =
            36: invokevirtual #6                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            39: iload_2                           // 就是变量表中第 2 个位置的 j 压栈到操作数栈顶 这里就是 j 了, 因为准备把 j 拼接到后面去
            40: invokevirtual #7                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
            43: invokevirtual #9                  // 调用 StringBuilder 的 toString 方法 Method java/lang/StringBuilder.toString:()Ljava/lang/String;
            46: invokevirtual #10                 // 调用 PrintStream 的 println 方法 Method java/io/PrintStream.println:(Ljava/lang/String;)V
            49: goto          58                  // break first 毫无征兆的跳到了 58 行
            52: iinc          1, 1
            55: goto          2
            58: iconst_0                         // 开始了 third 部分的循环
            59: istore_1
            60: iload_1
            61: bipush        10
            63: if_icmpge     79
            66: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
            69: iload_1
            70: invokevirtual #11                 // Method java/io/PrintStream.println:(I)V
            73: iinc          1, 1
            76: goto          60
            79: return
          LineNumberTable:
            line 8: 0
            line 10: 8
            line 11: 15
            line 12: 49
            line 8: 52
            line 17: 58
            line 18: 66
            line 17: 73
            line 20: 79
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
               10      42     2     j   I
                2      56     1     i   I
               60      19     1     a   I
                0      80     0  args   [Ljava/lang/String;
          StackMapTable: number_of_entries = 6
            frame_type = 252 /* append */
              offset_delta = 2
              locals = [ int ]
            frame_type = 252 /* append */
              offset_delta = 7
              locals = [ int ]
            frame_type = 250 /* chop */
              offset_delta = 41
            frame_type = 250 /* chop */
              offset_delta = 5
            frame_type = 252 /* append */
              offset_delta = 1
              locals = [ int ]
            frame_type = 250 /* chop */
              offset_delta = 18
    }
    SourceFile: "Main.java"
    

    常量入栈指令有 iconst, bipush, sipush, ldc, ldc2_w 分别对应不同的使用场景, 以下两个表简单总结了使用场景:

    • 八大基本类型场景表
      file
    • 指令场景表
      file

    上面的两张图片来自于: Java 逆向基础之常量入栈指令

    为啥要这么麻烦, 搞出这么多不通的入栈指令呢? 连 -1~5 这样的都要搞出来?

    • bipush 8 就是把 8 压到操作数栈中.
    • istore_1 就是操作数栈出栈, 存到本地变量表的第 1 位置;
    • iload_1, 就是变量表中第一个位置的 i 压栈到操作数栈顶
    • iinc 1 by 1, 就是变量表中第一个位置的
    • istore_1, 又把栈顶的 8 存回了变量表中的 i
    • dup 关于 dup 指令的作用, 在《深入理解 Java 虚拟机》这本书中是这么描述的. 这是一个操作数栈管理指令, 负责复制栈顶 (注意, 这个栈指的是操作数栈) 一个或者两个数值并将复制值或双份的复制值重新压人栈顶.
      简单理解就是给操作数栈栈顶的元素弄了一个备份.
      那么为什么要进行备份呢?
      一开始是 new 指令在堆上分配了内存并向操作数栈压入了指向这段内存的引用, 之后 dup 指令又备份了一份, 那么操作数栈顶就有两个, 再后是调用 invokespecial #18 指令进行初始化, 此时会消耗一个引用作为传给构造器的 this 参数, 那么还剩下一个引用, 会被 astore_1 指令存储到局部变量表中.dup 来自: Java 字节码 new 之后为什么会有 dup
    • invokespecial 的参数哪儿来的?
    • ldc: 则是从常量池中将常量

    Java 字节吗概述

    Java 虚拟机采用基于栈的架构, 其指令由操作码和操作数组成.

    操作码: 一个字节长度 (0~255), 意味着指令集的操作码个数不能操作 256 条.
    操作数: 一条指令可以有零或者多个操作数, 且操作数可以是 1 个或者多个字节. 编译后的代码没有采用操作数长度对齐方式, 比如 16 位无符号整数需使用两个字节储存 (假设为 byte1 和 byte2), 那么真实值是 (byte1 << 8) | byte2.
    放弃操作数对齐操作数对齐方案:

    优势: 可以省略很多填充和间隔符号, 从而减少数据量, 具有更高的传输效率;Java 起初就是为了面向网络, 智能家具而设计的, 故更加注重传输效率.
    劣势: 运行时从字节码里构建出具体数据结构, 需要花费部分 CPU 时间, 从而导致解释执行字节码会损失部分性能.

    指令介绍

    大多数指令包含了其操作所对应的数据类型信息, 比如 iload, 表示从局部变量表中加载 int 型的数据到操作数栈;而 fload 表示加载 float 型数据到操作数栈. 由于操作码长度只有 1Byte, 因此 Java 虚拟机的指令集对于特定操作只提供有限的类型相关指令, 并非为每一种数据类型都有相应的操作指令. 必要时, 有些指令可用于将不支持的类型转换为可被支持的类型.

    对于 byte,short,char,boolean 类型, 往往没有单独的操作码, 通过编译器在编译期或者运行期将其扩展. 对于 byte,short 采用带符号扩展,chart,boolean 采用零位扩展. 相应的数组也是采用类似的扩展方式转换为 int 类型的字节码来处理. 下面分门别类来介绍 Java 虚拟机指令, 都以 int 类型的数据操作为例.

    栈是指操作数栈.

    这两个部分来自:Jvm 系列 3—字节码指令

    字节码指令介绍:

    指令 含义
    aaload load onto the stack a reference from an array
    aastore store a reference in an array
    aconst_null push a null reference onto the stack
    aload load a reference onto the stack from a local variable #index
    aload_0 load a reference onto the stack from local variable 0
    aload_1 load a reference onto the stack from local variable 1
    aload_2 load a reference onto the stack from local variable 2
    aload_3 load a reference onto the stack from local variable 3
    anewarray create a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 | indexbyte2) in the constant pool
    areturn return a reference from a method
    arraylength get the length of an array
    astore store a reference into a local variable #index
    astore_0 store a reference into local variable 0
    astore_1 store a reference into local variable 1
    astore_2 store a reference into local variable 2
    astore_3 store a reference into local variable 3
    athrow throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable)
    baload load a byte or Boolean value from an array
    bastore store a byte or Boolean value into an array
    bipush push a byte onto the stack as an integer value
    breakpoint reserved for breakpoints in Java debuggers; should not appear in any class file
    caload load a char from an array
    castore store a char into an array
    checkcast checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 | indexbyte2)
    d2f convert a double to a float
    d2i convert a double to an int
    d2l convert a double to a long
    dadd add two doubles
    daload load a double from an array
    dastore store a double into an array
    dcmpg compare two doubles, 1 on NaN
    dcmpl compare two doubles, -1 on NaN
    dconst_0 push the constant 0.0 (a double) onto the stack
    dconst_1 push the constant 1.0 (a double) onto the stack
    ddiv divide two doubles
    dload load a double value from a local variable #index
    dload_0 load a double from local variable 0
    dload_1 load a double from local variable 1
    dload_2 load a double from local variable 2
    dload_3 load a double from local variable 3
    dmul multiply two doubles
    dneg negate a double
    drem get the remainder from a division between two doubles
    dreturn return a double from a method
    dstore store a double value into a local variable #index
    dstore_0 store a double into local variable 0
    dstore_1 store a double into local variable 1
    dstore_2 store a double into local variable 2
    dstore_3 store a double into local variable 3
    dsub subtract a double from another
    dup duplicate the value on top of the stack
    dup_x1 insert a copy of the top value into the stack two values from the top. value1 and value2 must not be of the type double or long.
    dup_x2 insert a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top
    dup2 duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long)
    dup2_x1 duplicate two words and insert beneath third word (see explanation above)
    dup2_x2 duplicate two words and insert beneath fourth word
    f2d convert a float to a double
    f2i convert a float to an int
    f2l convert a float to a long
    fadd add two floats
    faload load a float from an array
    fastore store a float in an array
    fcmpg compare two floats, 1 on NaN
    fcmpl compare two floats, -1 on NaN
    fconst_0 push 0.0f on the stack
    fconst_1 push 1.0f on the stack
    fconst_2 push 2.0f on the stack
    fdiv divide two floats
    fload load a float value from a local variable #index
    fload_0 load a float value from local variable 0
    fload_1 load a float value from local variable 1
    fload_2 load a float value from local variable 2
    fload_3 load a float value from local variable 3
    fmul multiply two floats
    fneg negate a float
    frem get the remainder from a division between two floats
    freturn return a float
    fstore store a float value into a local variable #index
    fstore_0 store a float value into local variable 0
    fstore_1 store a float value into local variable 1
    fstore_2 store a float value into local variable 2
    fstore_3 store a float value into local variable 3
    fsub subtract two floats
    getfield get a field value of an object objectref, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 | indexbyte2)
    getstatic get a static field value of a class, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 | indexbyte2)
    goto goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    goto_w goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 | branchbyte2 << 16 | branchbyte3 << 8 | branchbyte4)
    i2b convert an int into a byte
    i2c convert an int into a character
    i2d convert an int into a double
    i2f convert an int into a float
    i2l convert an int into a long
    i2s convert an int into a short
    iadd add two ints
    iaload load an int from an array
    iand perform a bitwise AND on two integers
    iastore store an int into an array
    iconst_m1 load the int value −1 onto the stack
    iconst_0 load the int value 0 onto the stack
    iconst_1 load the int value 1 onto the stack
    iconst_2 load the int value 2 onto the stack
    iconst_3 load the int value 3 onto the stack
    iconst_4 load the int value 4 onto the stack
    iconst_5 load the int value 5 onto the stack
    idiv divide two integers
    if_acmpeq if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_acmpne if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmpeq if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmpge if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmpgt if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmple if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmplt if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    if_icmpne if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifeq if value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifge if value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifgt if value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifle if value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    iflt if value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifne if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifnonnull if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    ifnull if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2)
    iinc increment local variable #index by signed byte const
    iload load an int value from a local variable #index
    iload_0 load an int value from local variable 0
    iload_1 load an int value from local variable 1
    iload_2 load an int value from local variable 2
    iload_3 load an int value from local variable 3
    impdep1 reserved for implementation-dependent operations within debuggers; should not appear in any class file
    impdep2 reserved for implementation-dependent operations within debuggers; should not appear in any class file
    imul multiply two integers
    ineg negate int
    instanceof determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    invokedynamic invokes a dynamic method and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    invokeinterface invokes an interface method on object objectref and puts the result on the stack (might be void); the interface method is identified by method reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    invokespecial invoke instance method on object objectref and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    invokestatic invoke a static method and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    invokevirtual invoke virtual method on object objectref and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    ior bitwise int OR
    irem logical int remainder
    ireturn return an integer from a method
    ishl int shift left
    ishr int arithmetic shift right
    istore store int value into variable #index
    istore_0 store int value into variable 0
    istore_1 store int value into variable 1
    istore_2 store int value into variable 2
    istore_3 store int value into variable 3
    isub int subtract
    iushr int logical shift right
    ixor int xor
    jsr† jump to subroutine at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 | branchbyte2) and place the return address on the stack
    jsr_w† jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 | branchbyte2 << 16 | branchbyte3 << 8 | branchbyte4) and place the return address on the stack
    l2d convert a long to a double
    l2f convert a long to a float
    l2i convert a long to a int
    ladd add two longs
    laload load a long from an array
    land bitwise AND of two longs
    lastore store a long to an array
    lcmp push 0 if the two longs are the same, 1 if value1 is greater than value2, -1 otherwise
    lconst_0 push 0L (the number zero with type long) onto the stack
    lconst_1 push 1L (the number one with type long) onto the stack
    ldc push a constant #index from a constant pool (String, int, float, Class, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, or a dynamically-computed constant) onto the stack
    ldc_w push a constant #index from a constant pool (String, int, float, Class, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, or a dynamically-computed constant) onto the stack (wide index is constructed as indexbyte1 << 8 | indexbyte2)
    ldc2_w push a constant #index from a constant pool (double, long, or a dynamically-computed constant) onto the stack (wide index is constructed as indexbyte1 << 8 | indexbyte2)
    ldiv divide two longs
    lload load a long value from a local variable #index
    lload_0 load a long value from a local variable 0
    lload_1 load a long value from a local variable 1
    lload_2 load a long value from a local variable 2
    lload_3 load a long value from a local variable 3
    lmul multiply two longs
    lneg negate a long
    lookupswitch a target address is looked up from a table using a key and execution continues from the instruction at that address
    lor bitwise OR of two longs
    lrem remainder of division of two longs
    lreturn return a long value
    lshl bitwise shift left of a long value1 by int value2 positions
    lshr bitwise shift right of a long value1 by int value2 positions
    lstore store a long value in a local variable #index
    lstore_0 store a long value in a local variable 0
    lstore_1 store a long value in a local variable 1
    lstore_2 store a long value in a local variable 2
    lstore_3 store a long value in a local variable 3
    lsub subtract two longs
    lushr bitwise shift right of a long value1 by int value2 positions, unsigned
    lxor bitwise XOR of two longs
    monitorenter enter monitor for object ("grab the lock" – start of synchronized() section)
    monitorexit exit monitor for object ("release the lock" – end of synchronized() section)
    multianewarray create a new array of dimensions dimensions of type identified by class reference in constant pool index (indexbyte1 << 8 | indexbyte2); the sizes of each dimension is identified by count1, [count2, etc.]
    new create new object of type identified by class reference in constant pool index (indexbyte1 << 8 | indexbyte2)
    newarray create new array with count elements of primitive type identified by atype
    nop perform no operation
    pop discard the top value on the stack
    pop2 discard the top two values on the stack (or one value, if it is a double or long)
    putfield set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    putstatic set static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 | indexbyte2)
    ret† continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional)
    return return void from method
    saload load short from array
    sastore store short to array
    sipush push a short onto the stack as an integer value
    swap swaps two top words on the stack (note that value1 and value2 must not be double or long)
    tableswitch continue execution from an address in the table at offset index
    wide execute opcode, where opcode is either iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, or ret, but assume the index is 16 bit; or execute iinc, where the index is 16 bits and the constant to increment by is a signed 16 bit short
    (no name) these values are currently unassigned for opcodes and are reserved for future use

    这个是我从 List of Java bytecode instructions 这里扣下来的.

    待完成

    字节码指令翻译.

    原文地址:Java 中有 goto 吗?

    欢迎访问我的博客: http://blog.duhbb.com/

  • 相关阅读:
    IOS 动画的各种实现方法
    多视图控制器--自动布局 3.5 4.0英寸的应用程序
    IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习
    TableView--通讯录--开篇
    UI 网络程序
    XML JSON解析--基本功能
    通讯录CoreData数据库实现版
    CoreData的使用入门到精通
    sqlite 数据类型详解
    189. Rotate Array
  • 原文地址:https://www.cnblogs.com/tuhooo/p/16356820.html
Copyright © 2020-2023  润新知