JVM | 字节码指令基础

  • 操作数栈管理指令

  • 1)pop、pop2:将操作数栈的栈顶一个或两个元素出栈。
    2)dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2:复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶。
    3)swap:将栈最顶端两个数值互换。

    public static void main(String[] args) {
        heavyMethod();
    }

    对应的字节码:

    public static void main(java.lang.String[]);
            Signature: ([Ljava/lang/String;)V
            flags: ACC_PUBLIC, ACC_STATIC
            Code:
                            stack=1, locals=1, args_size=1
                            0: invokestatic  #23                 // Method heavyMethod:()I
                            3: pop
                            4: return
            LineNumberTable:
                            line 115: 0
                            line 116: 4
    • 加载、存储指令

    1)iload、iload<n>、lload、lload<n>、fload、fload<n>、dload、dload<n>、aload、aload<n>:将一个局部变量加载到操作数栈。
    2)istore、istore<n>、lstore、lstore<n>、fstore、fstore<n>、dstore、dstore<n>、astore、astore<n>:将一个数值从操作数栈存储到局部变量表。
    3)bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconstm1、iconst<i>、lconst<l>、fconst<f>、dconst_<d>:将一个常量加载到操作数栈。
    4)wide:扩充局部变量表的访问索引的指令。

    public static int methodE(){
        int e = 100;
        int c = 300;
        int d = 300000;
        e++;
        ++e;
        --e;
        e--;
        return c + d + e;
    }

    对应的字节码:

    public static int methodE();
            Signature: ()I
            flags: ACC_PUBLIC, ACC_STATIC
            Code:
            stack=2, locals=3, args_size=0
            0: bipush        100
            2: istore_0
            3: sipush        300
            6: istore_1
            7: ldc           #5                  // int 300000
            9: istore_2
            10: iinc          0, 1
            13: iinc          0, 1
            16: iinc          0, -1
            19: iinc          0, -1
            22: iload_1
            23: iload_2
            24: iadd
            25: iload_0
            26: iadd
            27: ireturn
            LineNumberTable:
            line 40: 0
            line 41: 3
            line 42: 7
            line 43: 10
            line 44: 13
            line 45: 16
            line 46: 19
            line 47: 22
    • 运算指令

    1)iadd、ladd、fadd、dadd:加法指令。
    2)isub、lsub、fsub、dsub:减法指令。
    3)imul、lmul、fmul、dmul:乘法指令。
    4)idiv、ldiv、fdiv、ddiv:除法指令。
    5)irem、lrem、frem、drem:求余指令。
    6)ineg、lneg、fneg、dneg:取反指令。
    7)ishl、ishr、iushr、lshl、lshr、lushr:位移指令。
    8)ior、lor:按位或指令。
    9)iand、land:按位与指令。
    10)ixor、lxor:按位异或指令。
    11)iinc:局部变量自增指令。
    12)dcmpg、dcmpl、fcmpg、fcmpl、lcmp:比较指令。
    参照上例。

    • 类型转换指令

    1)int类型到long、float或者double类型,long类型到float、double类型,float类型到double类型:宽化类型转换(虚拟机直接支持)。
    2)i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f:窄化类型转换(显式指令)。

    public static void methodK(){
        int i = 97;
        short i2s = (short) i;
        char i2c = (char) i;
        long i2l = i;
        float i2f = i;
        double i2d = i;
        float l2f = i2l;
        double l2d = i2l;
    }

    对应的字节码:

    public static void methodK();
    Signature: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=11, args_size=0
         0: bipush        97
         2: istore_0
         3: iload_0
         4: i2s
         5: istore_1
         6: iload_0
         7: i2c
         8: istore_2
         9: iload_0
        10: i2l
        11: lstore_3
        12: iload_0
        13: i2f
        14: fstore        5
        16: iload_0
        17: i2d
        18: dstore        6
        20: lload_3
        21: l2f
        22: fstore        8
        24: lload_3
        25: l2d
        26: dstore        9
        28: return
      LineNumberTable:
        line 100: 0
        line 101: 3
        line 102: 6
        line 103: 9
        line 104: 12
        line 105: 16
        line 106: 20
        line 107: 24
        line 108: 28
    • 对象创建与访问指令

    1)new :创建类实例的指令。
    2)newarray、anewarray、multianewarray:创建数组的指令。
    3)getstatic、putstatic、getfield、putfield:访问类字段(类变量)和实例字段(实例变量)的指令。
    4)baload、caload、saload、iaload、laload、faload、daload、aaload:把一个数组元素加载到操作数栈的指令。
    5)bastore、castore、sastore、iastore、lastore、fastore、dastore、aastore:把一个操作数栈的值存储到数组元素中的指令。
    6)arraylength:取数组长度的指令。
    7)instanceof、checkcast:检查类实例类型的指令。

    public static void methodJ(){
        new SimpleMethodExecuteProcess();
    
        System.out.println(SimpleMethodExecuteProcess.i);
    }

    对应的字节码:

    public static void methodJ();
    Signature: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #9                  // class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess
         3: dup
         4: invokespecial #10                 // Method "<init>":()V
         7: pop
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: getstatic     #11                 // Field i:I
        14: invokevirtual #12                 // Method java/io/PrintStream.println:(I)V
        17: return
      LineNumberTable:
        line 91: 0
        line 93: 8
        line 94: 17
    • 控制转移指令

    1)ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne:条件分支。
    2)tableswitch、lookupswitch:复合条件分支。
    3)goto、goto_w、jsr、jsr_w、ret:无条件分支。

    public static void methodG(){
        if(i == 0){
            System.out.println(System.currentTimeMillis());
        }
    
        while(i < 1){
            System.out.println(System.currentTimeMillis());
            i++;
        }
    }

    对应的字节码:

        public static void methodG();
    Signature: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=0, args_size=0
         0: getstatic     #6                  // Field i:I
         3: ifne          15
         6: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: invokestatic  #7                  // Method java/lang/System.currentTimeMillis:()J
        12: invokevirtual #8                  // Method java/io/PrintStream.println:(J)V
        15: getstatic     #6                  // Field i:I
        18: iconst_1
        19: if_icmpge     42
        22: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        25: invokestatic  #7                  // Method java/lang/System.currentTimeMillis:()J
        28: invokevirtual #8                  // Method java/io/PrintStream.println:(J)V
        31: getstatic     #6                  // Field i:I
        34: iconst_1
        35: iadd
        36: putstatic     #6                  // Field i:I
        39: goto          15
        42: return
      LineNumberTable:
        line 62: 0
        line 63: 6
        line 66: 15
        line 67: 22
        line 68: 31
        line 70: 42
      StackMapTable: number_of_entries = 2
           frame_type = 15 /* same */
           frame_type = 26 /* same */
    • 异常处理指令

    athrow :显式抛出异常指令。

    public static void methodH(){
        try {
            throw new NullPointerException("nothing ...");
            // do nothing ...
        } catch (Throwable t){
            // do nothing ...
        }
    }

    对应的字节码:

    public static void methodH();
    Signature: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=0
         0: new           #9                  // class java/lang/NullPointerException
         3: dup
         4: ldc           #10                 // String nothing ...
         6: invokespecial #11                 // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
         9: athrow
        10: astore_0
        11: return
      Exception table:
         from    to  target type
             0    10    10   Class java/lang/Throwable
      LineNumberTable:
        line 77: 0
        line 79: 10
        line 82: 11
      StackMapTable: number_of_entries = 1
           frame_type = 74 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
    • 同步指令

    monitorenter、monitorexit:支持synchronized语句块语义的指令。

    public void methodI(){
        synchronized (Integer.class){
            // do nothing ...
        }
    }

    对应的字节码:

    public void methodI();
    Signature: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: ldc_w         #13                 // class java/lang/Integer
         3: dup
         4: astore_1
         5: monitorenter
         6: aload_1
         7: monitorexit
         8: goto          16
        11: astore_2
        12: aload_1
        13: monitorexit
        14: aload_2
        15: athrow
        16: return
      Exception table:
         from    to  target type
             6     8    11   any
            11    14    11   any
      LineNumberTable:
        line 88: 0
        line 90: 6
        line 91: 16
      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 11
          locals = [ class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
           frame_type = 250 /* chop */
          offset_delta = 4
    • synchronized 修饰方法的语义解析:可以直接从方法常量池的方法表结构中ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法,不需要解析出monitorenter、monitorexit同步指令。
    public static synchronized void methodL(){
        int i = 97;
    }
    
        public static synchronized void methodL();
            Signature: ()V
            flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
            Code:
                stack=1, locals=1, args_size=0
                     0: bipush        97
                     2: istore_0
                     3: return
                LineNumberTable:
                    line 120: 0
                    line 121: 3
    • 方法调用和返回指令

    1)invokestatic:调用静态方法。
    2)invokespecial:调用实例构造器<init>方法、私有方法和父类方法。
    3)invokevirtual:调用所有的虚方法。非虚方法以外的都是虚方法,非虚方法包括使用invokestatic、invokespecial调用的方法和被final修饰的方法。
    4)invokeinterface:调用接口方法,运行时再确定一个实现此接口的对象。
    5)invokedynamic:用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法。
    ireturn(返回值是boolean、byte、char、short、int)、lreturn、freturn、dreturn、areturn:方法返回指令。

    public static int heavyMethod(){
        int a = 200;
        int b = 100;
        int c = methodC(methodA(methodA(a, b), b), methodB(a, b));
        methodD();
        methodE();
        methodF();
        methodG();
        methodH();
        new SimpleMethodExecuteProcess().methodI();
        methodJ();
        methodK();
        methodL();
        return c;
    }

    对应的字节码:

    public static int heavyMethod();
    Signature: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=0
         0: sipush        200
         3: istore_0
         4: bipush        100
         6: istore_1
         7: iload_0
         8: iload_1
         9: invokestatic  #17                 // Method methodA:(II)I
        12: iload_1
        13: invokestatic  #17                 // Method methodA:(II)I
        16: iload_0
        17: iload_1
        18: invokestatic  #18                 // Method methodB:(II)I
        21: invokestatic  #19                 // Method methodC:(II)I
        24: istore_2
        25: invokestatic  #20                 // Method methodD:()V
        28: invokestatic  #21                 // Method methodE:()I
        31: pop
        32: invokestatic  #22                 // Method methodF:()D
        35: pop2
        36: invokestatic  #23                 // Method methodG:()V
        39: invokestatic  #24                 // Method methodH:()V
        42: new           #14                 // class edu/atlas/demo/java/jvm/SimpleMethodExecuteProcess
        45: dup
        46: invokespecial #15                 // Method "<init>":()V
        49: invokevirtual #25                 // Method methodI:()V
        52: invokestatic  #26                 // Method methodJ:()V
        55: invokestatic  #27                 // Method methodK:()V
        58: invokestatic  #28                 // Method methodL:()V
        61: iload_2
        62: ireturn
      LineNumberTable:
        line 128: 0
        line 129: 4
        line 130: 7
        line 131: 25
        line 132: 28
        line 133: 32
        line 134: 36
        line 135: 39
        line 136: 42
        line 137: 52
        line 138: 55
        line 139: 58
        line 140: 61

    原文地址:http://blog.51cto.com/damon188/2131035

    时间: 2024-12-13 00:41:53

    JVM | 字节码指令基础的相关文章

    从字节码指令看重写在JVM中的实现

    Java是解释执行的,包括动态链接的特性,都给解析或运行期间提供了很多灵活扩展的空间.面向对象语言的继承.封装和多态的特性,在JVM中是怎样进行编译.解析,以及通过字节码指令如何确定方法调用的版本是本文如下要探讨的主要内容,全文围绕一个多态的简单举例来看在JVM中是如何实现的. 先简单介绍几个概念.对于字节码执行模型及字节码指令集的相关概念可以参考之前的一篇介绍http://blog.csdn.net/lijingyao8206/article/details/46562933. 一.方法调用的

    JVM字节码之整型入栈指令(iconst、bipush、sipush、ldc)

    官网:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 原文地址:http://www.linmuxi.com/2016/02/25/jvm-int-pushstack-01/ 本篇主要分享下在JVM中int类型数值采用何种指令入栈的,根据int值范围JVM入栈字节码指令就分为4类,下面分别介绍下这四类指令. 前言 当int取值-1~5采用iconst指令,取值-128~127采用bipush指令,取值-32768~327

    JVM总括三-字节码、字节码指令、JIT编译执行

    JVM总括三-字节码.字节码指令.JIT编译执行 java文件编译后的class文件,java跨平台的中间层,JVM通过对字节码的解释执行(执行模式,还有JIT编译执行,下面讲解),屏蔽对操作系统的依赖.一个字节(8位)可以储存256中不同的指令,这样的指令就是字节码,java所有指令有200个左右,这些指令组成了字节码文件(.class). 一.字节码的主要指令: .class文件里面的十六进制文件(如:图一),其中CAFE BABE是标志这个文件为java的编译后的文件,00000034代表

    JVM字节码格式

    字节码格式 字节码是JVM的机器语言.JVM加载类文件时,对类中的每个方法,它都会得到一个字节码流.这些字节码流保存在JVM的方法区中.在程序运行过程中,当一个方法被调用时,它的字节码流就会被执行.根据特定JVM设计者的选择,它们可以通过解释的方式,即时编译(Just-in-time compilation)的方式或其他技术的方式被执行. 方法的字节码流就是JVM的指令(instruction)序列.每条指令包含一个单字节的操作码(opcode)和0个或多个操作数(operand).操作码指明要

    JVM总结(五):JVM字节码执行引擎

    JVM字节码执行引擎 运行时栈帧结构 局部变量表 操作数栈 动态连接 方法返回地址 附加信息 方法调用 解析 分派 –“重载”和“重写”的实现 静态分派 动态分派 单分派和多分派 JVM动态分派的实现 基于栈的字节码解释执行引擎 基于栈的指令集与基于寄存器的指令集 JVM字节码执行引擎 虚拟机是相对于“物理机”而言的,这两种机器都有代码执行能力,其区别主要是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的,而虚拟机的执行引擎是自己实现的.因此程序员可以自行制定指令集和执行引擎的

    jvm字节码简介

    1.概述 java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(成为操作码,Opcde)和跟随其后的0到多个此操作所需参数(操作数,Operands).由于操作码的长度为一个字节,所以指令集的操作数总数不能超过256条:又由于Class文件放弃了编译后代码的操作数对齐,所以虚拟机在处理超过一个字节的数据时会从字节中重建出具体的数据格式,例如一个16的长度的无符号整数会使用两个无符号字节存储(byte1.byte2),它们的值为  byte1 << 8 | byte2.对于大部分与

    深入理解java虚拟机(六)字节码指令简介

    Java虚拟机指令是由(占用一个字节长度.代表某种特定操作含义的数字)操作码Opcode,以及跟随在其后的零至多个代表此操作所需参数的称为操作数 Operands 构成的.由于Java虚拟机是面向操作数栈而不是寄存器的架构,所以大多数指令都只有操作码,而没有操作数. 字节码指令集是一种具有鲜明特点.优劣势都很突出的指令集架构: 由于限定了Java虚拟机操作码的长度为1个字节,指令集的操作码不能超过256条.Class文件格式放弃了编译后代码中操作数长度对齐,这就意味者虚拟机处理那些超过一个字节数

    字节码指令

    Java 虚拟机指令集所支持的数据类型: opcode byte short int long float double char reference Tipush bipush sipush Tconst iconst lconst fconst dconst aconst Tload iload lload fload dload aload Tstore istore lstore fstore dstore astore Tinc iinc Taload baload saload ia

    利用无效字节码指令引发逆向工具崩溃(二)

    上一节我们介绍了一种利用无效字节码指令引发逆向工具崩溃的方法.可惜的是大部分反编译工具已经修复了该bug.但是如果我们插入有效的字节码指令,但是后跟无效的数据引用,结果会是怎么样呢? 使用C32asm,以十六进制的方式打开dex文件.按快捷键"Ctrl + G",定位到"0003A2A4" 把"62 00 02 04 1A 01 8E 07 6E 20 19 10 10 00"改为"12 01 38 01 03 00 1A 00 FF