精华内容
下载资源
问答
  • 使用ILOAD/SIPUSH/IADD/ISTORE 也可以完成 IINC 的工作,主要是因为IINC是一个单指令,而前者则是4个,从存储空间上来说,可以节省一些空间, 在Java解释执行期间,解释一个指令也比解释执行4个指令效率要高些,当...

    使用 ILOAD/SIPUSH/IADD/ISTORE 也可以完成 IINC 的工作,主要是因为IINC是一个单指令,而前者则是4个,从存储空间上来说,可以节省一些空间,

    在Java解释执行期间,解释一个指令也比解释执行4个指令效率要高些,当使用JIT编译成本地代码执行后,则区别不大了。

    参考链接:https://stackoverflow.com/questions/37056714/why-does-java-have-an-iinc-bytecode-instruction

    展开全文
  • 相关实例均使用Oracle ...只有iinc指令例外,它直接对局部变量进行自增操作。 实例代码 int align2agrain(int i, int grain) { return ((i + grain - 1) & ~(grain - 1));} 字节码指令...

    相关实例均使用Oracle JDK 1.8编译,并使用javap生成字节码指令清单。

    算术运算

    Java虚拟机通常基于操作数栈进行算术运算。只有iinc指令例外,它直接对局部变量进行自增操作。

    实例代码

    int align2agrain(int i, int grain) {
        return ((i + grain - 1) & ~(grain - 1));
    }

    字节码指令序列



     

    以上指令,并没有出现取反的指令操作。因为JVM并没有提供取反指令,而是使用异或指令来实现取反。

    对一个数进行取反,相当于该数的二进制每一位与1进行异或操作。由于-1的补码二进制表示为全部都是1,因此对一个数进行取反,也相当于-1与该数进行异或。

    -1的原码、反码和补码表示

    [10000001]原=[11111110]反=[11111111]补

    异或实现取反

    ~x = -1^x

    访问运行时常量池

    实例代码

    void useManyNumeric() {
        int i = 100;
        int j = 1000000;
        long l1 = 1;
        long l2 = 0xffffffff;
        double d = 2.2;
    }

    字节码指令序列



     

    ldc、ldc_w:将int、float或String类型常量值从常量池中推送至栈顶。

    ldc2_w:将long、double类型常量值从常量池中推送至栈顶。(只有宽索引版本)

    其中,ldc_w和ldc2_w属于宽索引指令,即指令对应的(索引值)参数为2个字节。而ldc指令对应的(索引值)参数为1个字节。

    当运行时常量池中的常量个数超过256个(1个字节所能代表的数量)时,需要使用支持2个字节索引值的指令ldc_w指令来代替ldc访问常量池

    在局部变量表中,long和double类型的数据占用两个连续的局部变量,并且采用两个局部变量中较小的索引值来定位其数据
    因此,lstore_3、lstore 5、dstore 7 这三个指令实际存入的局部变量索引号分别为3和4、5和6、7和8。(局部变量表的索引值从0开始)

    控制结构

    Java虚拟机会根据数据类型的变化来生成不同的条件跳转语句。

    while实例1

    void whileInt() {
        int i = 0;
        while (i < 100) {
            i++;
        }
    }

    字节码指令序列



     

    iinc用于实现局部变量的自增操作。在所有字节码指令中,只有该指令可直接用于操作局部变量。

    对于循环的实现,将条件判断放在循环的最前面不是更易于理解,为什么要放在最后面?让我们来看看放在最前面的指令序列:

    2 iload_1
    3 bipush 100
    5 if_icmpge 14
    8 iinc 1,1
    11 goto 2

    显然,两种实现方式第1次循环都要执行5条执行。但对于后续的循环,前者只需要执行4条指令,而后者则需要执行5条指令。因此,将条件判断放在循环的最后面可以更高效的执行循环

    while实例2

    void whileDouble() {
        double i = 0;
        while (i < 100.1) {
            i++;
        }
    }

    字节码指令序列



     

    由于iinc只针对int类型的局部变量进行自增操作,JVM并没有提供相应的指令来操作double类型。因此,需要借助dadd来实现double类型的自增操作。

    同样,对于数值类型,以if开头的比较跳转指令,都只支持int类型(对于非数值类型,if比较跳转指令还支持引用类型数值)。因此,JVM另外提供了dcmpg、dcmpl来比较两个double类型数值的大小,然后将比较结果(1,0,-1)压入栈顶。最后,再使用int类型的if判断指令来进行判断跳转。

    dcmpg与dcmpl的区别仅在于,当比较的其中一个值为NaN时,dcmpg将1压入栈顶,而dcmpl将-1压入栈顶。

    ldc相关指令都是将常量值从常量池中推至栈顶,前面"访问运行时常量池"一节已经介绍过了。

    对于for循环分析,请看第一篇:JVM指令分析实例一(常量、局部变量、for循环)

    if实例1

    int lessThan100(double d) {
        if (d < 100.0) {
            return 1;
        } else {
            return -1;
        }
    }

    字节码指令序列



     

    if实例2

    int greaterThan100(double d) {
        if (d > 100.0) {
            return 1;
        } else {
            return -1;
        }
    }

    字节码指令序列



     

    if实例2与if实例1的差别仅在于比较符号由小于号改为大于号,因此ifge指令也相应的变成ifle指令。

    如果细心一点,还会发现一个差异,double比较指令由dcmpg变成了dcmpl。

    那么,JVM在什么情况下使用dcmpg,什么情况下又会使用dcmpl呢?为了理解这一点,我们需要先回顾一下浮点数中的NaN值。

    Java虚拟机关于浮点数的规范

    浮点类型包含float和double类型两种,32位单精度和64位双精度与IEEE 754格式的取值与操作是一致的。

    NaN值用于表示某此无效的运算操作,例如0除以0等情况。

    只要有操作数是NaN,那么对它进行任何数值比较和等值测试都会返回false。任何数值与NaN进行不等值比较都会返回true。

    有了以上知识,我们再回到例子来分析一下。

    我们知道,dcmpg与dcmpl的作用都是比较两个double类型数值的大小,并将结果(1,0,-1)压入栈顶。区别仅在于,当比较的其中一个值为NaN时,dcmpg将1压入栈顶,而dcmpl将-1压入栈顶。

    对于 if (d < 100.0) {},隐含了两个条件,一个是d必须小于100.0,另一个是d不能为NaN(如果为NaN会返回false)。因此,NaN属于该条件之外的情况。

    当 if (d < 100.0) {} 成立时,执行比较指令之后结果为-1。由于满足该条件时d不能为NaN,显然当d为NaN时比较结果不能为-1。因此比较指令排除dcmpl,只能使用dcmpg指令。

    维基百科对NaN的定义

    NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。

    返回NaN的运算有如下三种:



     

    参考

    《Java虚拟机规范》(Java SE 8版)

    NaN:https://zh.wikipedia.org/wiki/NaN

     

    转载请注明来源:http://zhanjia.iteye.com/blog/2431234

     

    个人公众号

    二进制之路

     

    展开全文
  • 刚写了个编文章说int i=i++的问题,之后想是iinc指令直接操作本地变量表草成的么,随之用long做了一下实验,看代码和编译后的指令, public static void iAdd(long i) { i = i++; System.out.println(i); } ...

    刚写了个编文章说int i=i++的问题,之后想是iinc指令直接操作本地变量表草成的么,随之用long做了一下实验,看代码和编译后的指令,


    public static void iAdd(long i) {
    		i = i++;
    		System.out.println(i);
    	}



    变异后的code的第1行的意思是复制栈顶一个(long、double型的)或两个(其它类型的)数值,并且复制值进栈,一直到第2行代码之后,这时候的栈是什么样子的呢?见下图

    1
    1
    1
    第三行ladd指令,栈顶两个元素出栈,相加之后入栈

     
    2
    1
    紧接着连续两个lstore指令,将栈顶元素存储到相应的本地变量表,弹出2之后本地变量i=2,弹出1之后本地变量i=1;

    后面的指令是输出语句的编译之后的指令,只做简单分析,6行获取常量池#3指示的静态域压入栈顶,9行加载本地变量表0出的变量到栈顶;

    10行栈顶两个元素出栈,调用#4 字符产量指定的函数。最后一行return。


    一些个人看法:

    i=i++;之所以会出现 执行完不变的情况,是因为:先用再加,按说先用i=i,再加i++;也不会出现不变的情况,应该是,先用,并不是真正的先用,而是在栈中暂时存储,并没有真正给本地变量表的变量赋值,知道i++结束之后,才将之前放入战中的值弹出赋值。


    这是i是long的情况下,去掉i=,之后编译后代码,发现少了一个dup2和lstore,也就是少了先用的入栈,和最后的出栈赋值。


    另外安利一个比较不错的文章,里面对变异后的指令均做了介绍,帮助甚大。

    JVM指令集(指令码、助记符、功能描述) --- 逐渐更新 --- 2011-08-23

    (最后又想起来一点,为什么栈的大小是3,因为所有的出栈入栈操作,栈大小为3即可满足所有的入栈出栈操作,最大时为3)

    展开全文
  • 字节码指令

    2019-10-20 11:06:39
    虚拟机是一个相对于物理机的概念,这两种机器都有代码执行能力,其区别在于物理机的执行引擎是直接建立在 CPU 处理器、指令集、操作系统和硬件层面上的。 而虚拟机的执行引擎则由自己实现,因此可以制定自己的指令集...

    虚拟机是一个相对于物理机的概念,这两种机器都有代码执行能力,其区别在于物理机的执行引擎是直接建立在 CPU 处理器、指令集、操作系统和硬件层面上的。

    而虚拟机的执行引擎则由自己实现,因此可以制定自己的指令集和执行引擎的结构体系,而且还可以执行一些不被硬件直接支持的指令集格式。这就是虚拟机相对于物理机的优势所在。

    但是缺点也比较明显,由于多了一层虚拟指令,执行虚拟机指令后还要转化为本地机器码,所以在执行效率上,虚拟机是不如物理机的。

    Java 虚拟机的字节码指令由一个字节长度的操作码(Opcode)以及紧随其后的零至多个操作数(Operands)构成。

    如果忽略异常处理,那么 Java 虚拟机的解释器通过下面这个伪代码的循环即可有效工作:

    do{
        自动计算pc寄存器以及从pc寄存器的位置取出操作码;
        if(存在操作数){
            取出操作数;
        }
        执行操作码所定义的操作;
    } while(处理下一次循环);
    

    由于字节码指令集限制了其操作码长度为 1 个字节(0 ~ 255),即意味着整个指令集中包含的指令总数不超过 256 条。

    在虚拟机处理超过 1 个字节的数据时,会在运行时重新构建出具体的数据结构。

    例如:如果要将一个 16 位无符号的整数使用两个无符号字节存储起来(命名为 byte1 和 byte2),那么这个 16 位无符号数的值应该这样表示:

    (byte1 << 8) | byte2
    

    这种操作在某种程度上会导致执行字节码时损失一些性能。但这样做的优势也非常明显,放弃了操作数长度对齐,就意味着可以节省很多填充和间隔符号;用一个字节来代表操作码,也是为了尽可能获得短小精干的编译代码。

    这种追求尽可能小数据量、高传输效率 的设计是由 Java 语言设计之初面向网络、智能家电的技术背景所决定的并沿用至今。

    字节码与数据类型

    在讲字节码指令之前,我们需要了解下,字节码指令操作的操作数是什么类型的,这些 Java 虚拟机中的数值类型又和 Java 编程语言中的 8 大基本数据类型如何对应的?

    Java 语言中的 8 大基本数据类型:

    • 整型:byte、short、int、long
    • 浮点型:double、float
    • 字符型:char
    • 布尔型:boolean

    Java 程序语言中定义了 8 大基本数据类型,但是在 Java 虚拟机中只分为两大类:

    • 原始类型(primitive type)
    • 引用类型(reference type)

    原始类型对应的数值称为原始值、引用类型的数值称为引用值。

    原始类型

    原始类型包括如下类型。

    • 数值类型

    数值类型包括:byte、short、int、long、char、float、double。

    • boolean 类型

    boolean 类型的值有两种:true 和 false,默认为 false,虽然在 Java 虚拟机中定义了 boolean 这种类型,但是却没有指令直接支持其操作。

    所以,对 boolean 类型都需要在编译后用虚拟机中的 int 类型来表示 —— 1 表示 true、0 表示 false。

    • returnAddress 类型

    returnAddress 类型表示一个指向某个操作码 opcode 的指针,此操作码与虚拟机指令相对应。

    引用类型

    引用类型包括如下类型。

    • 类类型(class type)
    • 数组类型(array type)
    • 接口类型(interface type)

    这三种引用类型的值分别指向动态创建的类实例、数组实例和实现了某个接口的类/数组实例。

    在引用类型中还有一个特殊的值 null,当一个引用不指向任何对象时,它就用 null 表示, null 作为引用类型的初始默认值可以转型成任意的引用类型。

    加载与存储指令

    加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输,这类指令包括如下内容。

    • 将一个局部变量加载到操作数栈

    iloadiload_<n>lload,load<n>fload,fload_<n>dload,dload_<n>aload,aload_<n>

    • 将一个数值从操作数栈存储到局部变量表

    istoreistore_<n>lstorelstore_<n>fstore,fstore_<n>dstoredstore_<n>astore,astore_<n>

    • 将一个常量加载到操作数栈

    bipushsipushldcldc_wldc2_waconst_nulliconst_m1iconst_<i>lconst_<l>fconst_<f>dconst_<d>

    • 扩充局部变量表的访问索引:wide

    上面所列举的指令助记符中,有一部分是以 _<n> 尾的,这些指令助记符实际上是代表了一组指令。

    如:iload_<n> 代表了 iload_0、iload_1、iload_2 和 iload_3这几条指令,此时操作数隐藏于指令之中。

    iload_0 表示从当前栈帧局部变量表中 0 号位置取 int 类型的数值加载到操作数栈
    iload_1 表示从当前栈帧局部变量表中 1 号位置取 int 类型的数值加载到操作数栈
    ...
    

    运算指令

    算术指令用于对两个操作数栈上的值进行某种特定运算,并把结构重新压入操作数栈。

    大体上算术指令可以分为两种:对整型数据进行运算的指令和对浮点类型数据进行运算的指令。

    在每一大类中,都有针对 Java 虚拟机具体数据类型的专用算术指令。但没有直接支持 byte、short、char 和 boolean 类型的算术指令,对于这些数据的运算,都是用 int 类型指令来处理。

    所有算术指令包括:

    • 加法指令:iadd、ladd、fadd、dadd
    • 减法指令:isub、lsub、fsub、dsub
    • 乘法指令:imul、lmul、fmul、dmul
    • 除法指令:idiv、ldiv、fdiv、ddiv
    • 求余指令:irem、lrem、frem、drem
    • 求负值指令:ineg、lneg、fneg、dneg
    • 移位指令:ishl、ishr、iushr、lshl、lshr、lushr
    • 按位或指令:ior、lor
    • 按位与指令:iand、land
    • 按位异或指令:ixor、lxor
    • 局部变量自增指令:iinc
    • 比较指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp

    类型转换指令

    类型转换指令可以在两种 Java 虚拟机数值类型之间相互转换。这些转换操作一般用于实现用户代码中的显式类型转换操作,或者用来解决 Java 虚拟机字节码指令的不完备问题。

    Java 虚拟机直接支持以下数值的宽化类型转换(widening numeric conversion,小范围类型向大范围类型的安全转换):

    • 从 int 类型到 long、float 或者 double 类型
    • 从 long 类型到 float、double 类型
    • 从 float 类型到 double 类型

    宽化类型转换指令包括:i2l、i2f、i2d、l2f、l2d 和 f2d。

    Java 虚拟机也支持以下窄化类型转换:

    • 从 int 类型到 byte、short 或者 char 类型
    • 从 long 类型到 int 类型
    • 从 float 类型到 int 或者 long 类型
    • 从 double 类型到 int、long 或者 float 类型

    窄化类型转换(narrowing numeric conversion)指令包括:i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f。

    对象创建与访问指令

    在 Java 中类实例和数组都是对象,但是 Java 虚拟机对类 class 对象和数组对象的创建使用了不同的字节码指令。

    • 创建类实例的指令:new
    • 创建数组的指令:newarray、anewarray、multianewarray
    • 访问类变量(static 字段)的指令:getstatic、putstatic
    • 访问实例变量的指令:getfield、putfield
    • 将一个数组元素加载到操作数栈的指令:baload、caload、saload、iaload、laload、faload、daload、aaload
    • 将一个操作数栈的值存到数组元素中的指令:bastore、castore、sastore、iastor、fastore、dastore、aastore
    • 取数组长度的指令:arraylength
    • 检查类实例类型的指令:instanceof、checkcast

    操作数栈管理指令

    Java 虚拟机提供了一些用于直接操控操作数栈的指令,包括:pop、pop2、dup、dup2、dup_x1、dup_x2、dup2_x1、dup_x2、dup2_x2 和 swap。

    控制转移指令

    控制转移指令可以让 Java 虚拟机有条件或无条件地从指定指令而不是控制转移指令的下一条指令继续执行程序。

    控制指令包括:

    • 条件分支

    ifeq、iflt、ifle、ifne、ifgt、ifge、jfnull、ifnonnull、ificmpeq、ificmpne、ificmplt、ificmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne

    • 符合条件分支

    tableswitch、lookupswitch

    • 无条件分支

    goto、goto_w、jsr、jsr_w、ret

    方法调用与返回指令

    以下 5 条指令用于方法调用:

    • invokevirtual

    用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是 Java 语言中最常见的方法分派方式。

    • invokeinterface

    用于调用接口方法,它会在运行时搜索一个实现了此接口的对象,找出合适的方法进行调用。

    • invokestatic

    用于调用类方法(static 方法)。

    • invokedynamic

    指令用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法,前面的 4 条调用指令的分派逻辑都固话在 Java 虚拟机内部,而 invokedynamic 指令的分派逻辑则是由用户所设定的引导方法所决定的。

    异常处理指令

    在 Java 程序中显示抛出异常的操作(throw 语句)都由 athrow 指令来实现,除了用 throw 语句显示抛出的异常以外,Java 虚拟机规范还规定了许多会在 Java 虚拟机检查到异常状况时自动抛出的运行时异常。

    如:在整数运算中,当除数为 0 时,虚拟机会在 idiv 或 ldiv 指令中抛出 ArithmeticException 异常。

    此处需要注意的是,在 Java 虚拟机中处理异常(catch 语句)不是由字节码指令实现的,而是采用异常处理器(异常表)来完成的。

    同步指令

    Java 虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,两种同步都是使用管程(Monitor)来支持的。

    • 方法级的同步

    方法级的同步时隐式的,即无需通过字节码指令控制,它实现在方法调用和返回操作之中。虚拟机可以从方法常量池的方法表中 ACC_SYNCHRONIZED 访问标志得知此方法是否声明为同步方法。

    当方法调用时,如果此方法为同步方法,则执行线程就要去先成功持有管程,然后才能执行方法,方法(无论是否正常完成)完成后释放管程。

    如果这个同步方法执行期间抛出异常,并且方法内部无法处理,那么此方法持有的管程将在异常抛出去后自动释放。

    • 指令序列级的同步

    同步一段指令序列通常是由 Java 中的 synchronized 语句块来表示的,Java 虚拟机指令集中有 monitorenter 和 monitorexit 两条指令来支持 synchronized 关键字。

    附录

    参考资料

    • 《深入理解 Java 虚拟机》
    • 《Java 虚拟机规范 SE 8 版》

    我的 GitHub

    github.com/jeanboydev

    我的公众号

    欢迎关注我的公众号,分享各种技术干货,各种学习资料,职业发展和行业动态。

    Android 波斯湾

    技术交流群

    欢迎加入技术交流群,来一起交流学习。

    QQ 技术交流群
    微信技术交流群
    展开全文
  • 二、所有算术指令 三、彻底搞懂i++与++i的问题 四、比较指令的说明 一、概述 算术指令用于对两个操作数栈上的值进行某种特定运算,并把计算之后的结果重新压入操作数栈中。 【a】算术指令大体上可以分为两种: ...
  • 目录 一、概述 二、比较指令 三、条件跳转指令 ...比较指令属于算术指令,比较指令的说明: 比较指令的作用是比较栈顶两个元素的大小,并将比较结果入栈。 比较指令有: dcmpg、dcmpl、 fcmpg、.
  • JVM之类加载

    2021-01-06 10:28:05
    字节码技术分析a++ 练习 - 分析 i++ 目的:从字节码角度分析 a++ 相关题目 ...1.注意 iinc 指令是直接在局部变量 slot 上进行运算 2.a++ 和 ++a 的区别是先执行 iload 还是 先执行 iinc ...
  • javap指令

    2019-06-03 09:58:06
    javap指令栈和局部变量操作将常量压入栈的指令通用(无类型)栈操作类型转换整数运算逻辑运算移位操作按位布尔运算浮点运算对象和数组对象操作指令数组操作指令控制流条件分支指令比较指令无条件转移指令异常方法调用...
  • 虚拟机字节码指令

    千次阅读 2019-03-13 21:23:00
    指令含义 0x00 nop None 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int型0推送至栈顶 0x04 iconst_1 将int型1推送至栈顶 ...
  • JVM指令

    千次阅读 2016-12-17 22:57:04
    原文:http://blog.csdn.net/lm2302293/article/details/6713147 JVM指令集(指令码、助记符、功能描述)指令码助记符功能... 指令执行前指令执行后栈底...... null栈顶 注意:JVM并没有为null指派一个具体的值。 
  • Java 指令与字节码

    2019-05-10 12:25:29
    Java 指令与字节码查看class文件编写简单java代码编译代码查看class文件Java字节码总的结构表常量池常量池容量计数器 鉴于十进制的计算机还遥遥无期,我们目前的计算机都是二进制的计算机,而二进制的计算机仅能识别...
  • 深入理解Java虚拟机--字节码指令

    万次阅读 2017-05-07 00:31:14
    《深入理解Java虚拟机JVM高级特性与最佳实践》附录B 虚拟机字节码指令表 字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1...
  • 前边我们说了class的组成部分,但是对于JVM是用什么指令进行执行各种操作呢?由于更多的是理论知识点,这里找了一篇比较全的,条理也不叫清楚。这样我们就知道我们写的Java代码,对应的JVM的指令集了。多了解,需要...
  • JVM指令手册

    2019-09-13 10:54:28
    文章目录栈和局部变量操作将常量压入栈的指令将栈中的值存入局部变量的指令wide指令通用(无类型)栈操作类型转换整数运算逻辑运算移位操作按位布尔运算浮点运算对象和数组对象操作指令数组操作指令控制流条件分支...
  • 揭开指令码的神秘面纱
  • JVM指令集(1).docx

    2020-06-03 18:31:08
    jvm常用的指令,是分析字节码反汇编的必备指令 常用的指令 > iconst_0 将int类型常量0压入栈 > istore_1 将int类型值存入局部变量1 > iconst_0 将int类型常量0压入栈 > istore_2 将int类型值存入局部变量2 > iload_1...
  • 最近在看JVM虚拟机,想要搞懂虚拟机的内部运行机制,指令码的分析是必不可少的!来看一个简单的测试小程序,看看里面的运行机制!这里就需要借助javap命令去查看了! 第一步,创建一个简单的测试程序 第二步,...
  • 字节码指令详解

    万次阅读 2020-08-05 16:49:04
    在计算机中,CPU指令就是指挥机器工作的指令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是执行指令的过程,也就是计算机的工作过程。 通常一条CPU指令包括两方面的内容:操作码和操作数,操作码表示要...
  • 字节码文件的学习

    2020-05-02 01:14:26
    关于a++和++a java 学习之路 int a = 10; int b = a++ + ++a + a-- + --a; System.out.println(a); System.out.println(b);...使用 javap -v Demo.class 得到反编译...iinc 指令是在局部变量 solt 直接运算 0: bipus...
  • JVM指令

    2019-03-12 14:33:38
    iinc 将指定的int变量增加指定值(i++,i--,i+=2); i2l 将栈顶int类型数据强制转换成long型将结果压入到栈顶; lcmp 将栈顶两long型数据的大小进行比较,并将结果(1,0,-1)压入栈顶; 以if开头的指令都是...
  •  java虚拟机通常在操作数栈上进行算术运算(例外情况是iinc指令,它直接增加一个局部变量的值)。例如下面的align2grain()方法,它的作用是将int值对齐到2的指定次幂: int align2grain(int i, int grain) { ...
  • javap 指令

    2018-09-23 21:24:24
    一、未归类系列A 二、const系列 ...九、自增减指令 ...十一、比较指令系列A ...十二、有条件跳转指令系列A ...十三、无条件跳转指令系列A ...十四、返回指令系列...
  • 常量入栈指令 指令码 操作码(助记符) 操作数 描述(栈指操作数栈) 0x01 aconst_null 将 null推送至栈顶 0x02 iconst_m1 将 -1(int)推送至栈顶 0x03 iconst_0 将 0(int)推送至栈顶 0x04 iconst_1...
  • 专栏原创出处:github-源笔记文件 ,...Java 虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(操作码)以及跟随其后的零至多个代表此操作所需的参数(操作数)构成。 如果不考虑异常处理的话,那...
  • 1.反编译指令: javap -c xxx.class 2.jvm指令集  JVM指令集(指令码、助记符、功能描述) 指令码 助记符 功能描述 0x00 nop 无操作   ...
  • JVM指令详解(下)

    2015-10-08 22:02:50
    九、自增减指令指令用于对本地(局部)变量进行自增减操作。该指令第一参数为本地变量的编号,第二个参数为自增减的数量。 比如对于代码: int d=10; ...其指令为: ... 5:iinc 2, 1//在我的程序中是其所...
  • JVM字节码指令

    2021-05-21 23:44:17
    JVM指令表常量型本地变量数组变量类型将值存入变量将值存入数组将值弹出栈顶复制栈顶数值指令数据交换指令变量计算变量增加指定值跳转指令返回指令获值/赋值指令调用方法指令创建对象指令异常指令指令 常量型 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,645
精华内容 1,058
热门标签
关键字:

iinc指令