`
glutinit
  • 浏览: 46026 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM摘要--指令集介绍01

    博客分类:
  • JVM
阅读更多
    一个JVM的指令包含了1个字节的操作码,该操作码用来表示要操作的动作,然后是0个或多个表示操作码的操作对象:参数或者其他数据。许多指令都没有操作数,而只有一个操作码。
    不考虑异常的损耗,JVM解释器的内循环是很有效率的:
do{
atomically calculate pc and fetch opcode at pc;
                If (operands) fetch operands;
                execute the action for the opcode;
        }while(there is more to do)

     操作数的数量和大小由操作码决定。比如,如果一个16-bit大小的索引要存放在局域变量中,则要存放在2个字节中,记为byte1和byte2,所以这样存放的变量,其所表达的值为(byte1<<8)|byte2。

1.类型和JVM

    大多数JVM中的指令集都要求它们要操作的动作所涉及的类型设定为一种。比如,iLoad指令表示从局部变量中加载的值必须是int类型的。同理,fload也要求加载的值的类型需要时float。这两个指令有相似的应用,但却有不同的操作数。

    大多数带有类型要求的指令,指令的类型可以通过字母明显的看出。比如,i表示针对int的操作,l表示long,s表示short,b表示byte,c表示char,f表示float,d表示double,而a表示reference。而有些命令则没有表示类型的字母,比如arrayLength通常都是针对一个数组的操作。而一些类似goto的命令,则不操作带有类型信息的操作数。

    从下面的表中,可以看出很多含有类型标注的指令。其中大多数的指中,byte,char和short都是空的。并且其中没有看到boolean的相关内容。怎么回事呢?在编译或运行时,编译器会将byte和short的值利用符号扩展变为int的值,然后再加以使用。而boolean和char的值则利用了0填充的方法将其值转换为int。

     同样,从数组中加载boolean,short,byte,和char的值都被JVM在编译或运行期利用符号扩展或0扩展转变成了int类型的值。可以说,boolea,byte,char和short的操作与int的操作用的是一样的指令。
    
    
      2. Load和Store指令

load和store指令是指操作数栈和局部变量区中的值的互相传递,局部变量区(local variables)和操作数栈(operand stack)都属于JVM帧(frame),这些指令包括:

• Load a local variable onto the operand stack: iload, iload_<n>, lload, lload_<n>, fload, fload_<n>, dload, dload_<n>, aload, aload_<n>.
• Store a value from the operand stack into a local variable: istore, istore_<n>,lstore, lstore_<n>, fstore, fstore_<n>, dstore, dstore_<n>, astore, astore_<n>.
• Load a constant onto the operand stack: bipush, sipush, ldc, ldc_w, ldc2_w,aconst_null, iconst_m1, iconst_<i>, lconst_<l>, fconst_<f>, dconst_<d>.
• Gain access to more local variables using a wider index, or to a larger immediate operand: wide.

3.算术指令
    算术指令,一般都是从操作数栈中获得两个操作数,然后这两个数计算得到结果放回到操作数栈中。根据操作数的类型分,有两大类的算术指令,一是操作整数的指令;一是操作浮点类型的指令。没有直接操作byte,short,char或boolean类型的算术指令,它们都被视为int来进行操作。整数和浮点类型的操作指令的区别还体现在对“溢出”和“被0除”的行为上。算术指令包括:
    • Add: iadd, ladd, fadd, dadd.
    • Subtract: isub, lsub, fsub, dsub.
    • Multiply: imul, lmul, fmul, dmul.
    • Divide: idiv, ldiv, fdiv, ddiv.
    • Remainder: irem, lrem, frem, drem.
    • Negate: ineg, lneg, fneg, dneg.
    • Shift: ishl, ishr, iushr, lshl, lshr, lushr.
    • Bitwise OR: ior, lor.
    • Bitwise AND: iand, land.
    • Bitwise exclusive OR: ixor, lxor.
    • Local variable increment: iinc.
    • Comparison: dcmpg, dcmpl, fcmpg, fcmpl, lcmp.

   JVM不会表示出整数类型的“溢出”。只有当除数为0的时候,针对int的操作才会抛出ArithmeticException,会跑出该异常的指令有:idiv, ldiv, irem,lrem; 针对浮点类型的指令遵循IEEE 754的标准。

4.转型指令

    转换指令允许JVM的数字类型之间进行转型。

   JVM支持一下几种向上转型:
   •int to long, float, or double 指令为 i2l, i2f,i2d
   •long to float or double          指令为l2f,l2d
   •float to double     指令为f2d

     其中,i2l, i2d, f2d这三个转型指令不会发生精度丢失的问题。而i2f, l2f, l2d 这三个转型指令可能会有精度丢失的问题,即它们回让最低有效位的一些值丢失.除去有可能的精度丢失,向上转型不会让JVM抛出Runtime Exception;

以及几种向下转型:

  •int to byte, short, or char 指令为i2b,i2s,i2c
  •long to int         指令为l2i
  •float to int or long         指令为f2i,f2l
  •double to int, long, or float 指令为d2i,d2l,d2f

    显然,向下转型会引起精度丢失,有可能会让数字的正负号发生变化,有可能会让数量发生变化,或者两者都变化。一般来说向下转型要谨慎使用…很多bug都隐藏在向下转型中~

       
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics