乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      深入了解Bytecode

       hmtomyang 2012-03-30
      二、Bytecode

      1,什么是Bytecode
      C/C++編譯器把源代碼編譯成匯編代碼,Java編譯器把Java源代碼編譯成字節(jié)碼bytecode。
      Java跨平臺其實就是基于相同的bytecode規(guī)范做不同平臺的虛擬機,我們的Java程序編譯成bytecode后就可以在不同平臺跑了。
      .net框架有IL(intermediate language),匯編是C/C++程序的中間表達方式,而bytecode可以說是Java平臺的中間語言。
      了解Java字節(jié)碼知識對debugging、performance tuning以及做一些高級語言擴展或框架很有幫助。

      2,使用javap生成Bytecode
      JDK自帶的javap.exe文件可以反匯編Bytecode,讓我們看個例子:
      Test.java:
      Java代碼 復(fù)制代碼 收藏代碼
      1. public class Test {  
      2.   public static void main(String[] args) {  
      3.     int i = 10000;  
      4.     System.out.println("Hello Bytecode! Number = " + i);  
      5.   }  
      6. }  

      編譯后的Test.class:
      Java代碼 復(fù)制代碼 收藏代碼
      1. 漱壕   1 +  
      2.           
      3.      
      4.     
      5.     
      6.     
      7.      <init> ()V Code LineNumberTable main ([Ljava/lang/String;)V   
      8. SourceFile   Test.java      
      9.     ! " java/lang/StringBuilder Hello Bytecode! Number =   # $  # %  & ' (  ) * Test java/lang/Object java/lang/System out Ljava/io/PrintStream; append -(Ljava/lang/String;)Ljava/lang/StringBuilder; (I)Ljava/lang/StringBuilder; toString ()Ljava/lang/String; java/io/PrintStream println (Ljava/lang/String;)V !   
      10.              
      11.           *                      >     '<  Y                              

      使用javap -c Test > Test.bytecode生成的Test.bytecode:
      Java代碼 復(fù)制代碼 收藏代碼
      1. Compiled from "Test.java"  
      2. public class Test extends java.lang.Object{  
      3. public Test();  
      4.   Code:  
      5.    0:  aload_0  
      6.    1:  invokespecial  #1//Method java/lang/Object."<init>":()V  
      7.    4:  return  
      8.   
      9. public static void main(java.lang.String[]);  
      10.   Code:  
      11.    0:  sipush  10000  
      12.    3:  istore_1  
      13.    4:  getstatic  #2//Field java/lang/System.out:Ljava/io/PrintStream;  
      14.    7:  new  #3//class java/lang/StringBuilder  
      15.    10:  dup  
      16.    11:  invokespecial  #4//Method java/lang/StringBuilder."<init>":()V  
      17.    14:  ldc  #5//String Hello Bytecode! Number =   
      18.    16:  invokevirtual  #6//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;  
      19.    19:  iload_1  
      20.    20:  invokevirtual  #7//Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;  
      21.    23:  invokevirtual  #8//Method java/lang/StringBuilder.toString:()Ljava/lang/String;  
      22.    26:  invokevirtual  #9//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
      23.    29:  return  
      24.   
      25. }  

      JVM就是一個基于stack的機器,每個thread擁有一個存儲著一些frames的JVM stack,每次調(diào)用一個方法時生成一個frame。
      一個frame包括一個local variables數(shù)組(本地變量表),一個Operand LIFO stack和運行時常量池的一個引用。

      我們來簡單分析一下生成的字節(jié)碼指令:
      aload和iload指令的“a”前綴和“i”分別表示對象引用和int類型,其他還有“b”表示byte,“c”表示char,“d”表示double等等
      我們這里的aload_0表示將把local variable table中index 0的值push到Operand stack,iload_1類似
      invokespecial表示初始化對象,return表示返回
      sipush表示把10000這個int值push到Operand stack
      getstatic表示取靜態(tài)域
      invokevirtual表示調(diào)用一些實例方法
      這些指令又稱為opcode,Java一直以來只有約202個Opcode,具體請參考Java Bytecode規(guī)范。

      我們看到Test.class文件不全是二進制的指令,有些是我們可以識別的字符,這是因為有些包名、類名和常量字符串沒有編譯成二進制Bytecode指令。

      3,體驗字節(jié)碼增強的魔力
      我們J2EE常用的Hibernate、Spring都用到了動態(tài)字節(jié)碼修改來改變類的行為。
      讓我們通過看看ASM的org.objectweb.asm.MethodWriter類的部分方法來理解ASM是如何修改字節(jié)碼的:
      Java代碼 復(fù)制代碼 收藏代碼
      1. class MethodWriter implements MethodVisitor {  
      2.   
      3.     private ByteVector code = new ByteVector();  
      4.   
      5.     public void visitIntInsn(final int opcode, final int operand) {  
      6.         // Label currentBlock = this.currentBlock;  
      7.         if (currentBlock != null) {  
      8.             if (compute == FRAMES) {  
      9.                 currentBlock.frame.execute(opcode, operand, nullnull);  
      10.             } else if (opcode != Opcodes.NEWARRAY) {  
      11.                 // updates current and max stack sizes only for NEWARRAY  
      12.                 // (stack size variation = 0 for BIPUSH or SIPUSH)  
      13.                 int size = stackSize + 1;  
      14.                 if (size > maxStackSize) {  
      15.                     maxStackSize = size;  
      16.                 }  
      17.                 stackSize = size;  
      18.             }  
      19.         }  
      20.         // adds the instruction to the bytecode of the method  
      21.         if (opcode == Opcodes.SIPUSH) {  
      22.             code.put12(opcode, operand);  
      23.         } else { // BIPUSH or NEWARRAY  
      24.             code.put11(opcode, operand);  
      25.         }  
      26.     }  
      27.   
      28.     public void visitMethodInsn(  
      29.         final int opcode,  
      30.         final String owner,  
      31.         final String name,  
      32.         final String desc)  
      33.     {  
      34.         boolean itf = opcode == Opcodes.INVOKEINTERFACE;  
      35.         Item i = cw.newMethodItem(owner, name, desc, itf);  
      36.         int argSize = i.intVal;  
      37.         // Label currentBlock = this.currentBlock;  
      38.         if (currentBlock != null) {  
      39.             if (compute == FRAMES) {  
      40.                 currentBlock.frame.execute(opcode, 0, cw, i);  
      41.             } else {  
      42.                 /* 
      43.                  * computes the stack size variation. In order not to recompute 
      44.                  * several times this variation for the same Item, we use the 
      45.                  * intVal field of this item to store this variation, once it 
      46.                  * has been computed. More precisely this intVal field stores 
      47.                  * the sizes of the arguments and of the return value 
      48.                  * corresponding to desc. 
      49.                  */  
      50.                 if (argSize == 0) {  
      51.                     // the above sizes have not been computed yet,  
      52.                     // so we compute them...  
      53.                     argSize = getArgumentsAndReturnSizes(desc);  
      54.                     // ... and we save them in order  
      55.                     // not to recompute them in the future  
      56.                     i.intVal = argSize;  
      57.                 }  
      58.                 int size;  
      59.                 if (opcode == Opcodes.INVOKESTATIC) {  
      60.                     size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;  
      61.                 } else {  
      62.                     size = stackSize - (argSize >> 2) + (argSize & 0x03);  
      63.                 }  
      64.                 // updates current and max stack sizes  
      65.                 if (size > maxStackSize) {  
      66.                     maxStackSize = size;  
      67.                 }  
      68.                 stackSize = size;  
      69.             }  
      70.         }  
      71.         // adds the instruction to the bytecode of the method  
      72.         if (itf) {  
      73.             if (argSize == 0) {  
      74.                 argSize = getArgumentsAndReturnSizes(desc);  
      75.                 i.intVal = argSize;  
      76.             }  
      77.             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 20);  
      78.         } else {  
      79.             code.put12(opcode, i.index);  
      80.         }  
      81.     }  
      82. }  

      通過注釋我們可以大概理解visitIntInsn和visitMethodInsn方法的意思。
      比如visitIntInsn先計算stack的size,然后根據(jù)opcode來判斷是SIPUSH指令還是BIPUSH or NEWARRAY指令,并相應(yīng)的調(diào)用字節(jié)碼修改相關(guān)的方法。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多