隨筆-204  評(píng)論-149  文章-0  trackbacks-0
          查到一篇使用BCEL了,Java 編程的動(dòng)態(tài)性,第 7 部分: 用 BCEL 設(shè)計(jì)字節(jié)碼,網(wǎng)址是http://www-128.ibm.com/developerworks/cn/java/j-dyn0414/

          字節(jié)碼處理的工具也挺多,什么時(shí)候再看看asm
          import java.io.FileOutputStream;

          import org.apache.bcel.Constants;
          import org.apache.bcel.classfile.ClassParser;
          import org.apache.bcel.classfile.JavaClass;
          import org.apache.bcel.classfile.Method;
          import org.apache.bcel.generic.ClassGen;
          import org.apache.bcel.generic.ConstantPoolGen;
          import org.apache.bcel.generic.GETSTATIC;
          import org.apache.bcel.generic.INVOKEVIRTUAL;
          import org.apache.bcel.generic.InstructionConstants;
          import org.apache.bcel.generic.InstructionFactory;
          import org.apache.bcel.generic.InstructionList;
          import org.apache.bcel.generic.MethodGen;
          import org.apache.bcel.generic.ObjectType;
          import org.apache.bcel.generic.PUSH;
          import org.apache.bcel.generic.Type;



          public class BCELTiming {
              
              
              
          private static void addWrapper(ClassGen cgen,Method method){
                  
          //set up the construction tools
                  InstructionFactory ifact = new InstructionFactory(cgen);
                  InstructionList ilist 
          = new InstructionList();
                  ConstantPoolGen pgen 
          = cgen.getConstantPool();
                  String cname 
          = cgen.getClassName();
                  MethodGen wrapgen 
          = new MethodGen(method,cname,pgen);
                  wrapgen.setInstructionList(ilist);
                  
                  
          //rename a copy of the original method
                  MethodGen methgen = new MethodGen(method,cname,pgen);
                  cgen.removeMethod(method);
                  String iname 
          = methgen.getName()+"$impl";
                  methgen.setName(iname);
                  cgen.addMethod(methgen.getMethod());
                  Type returnType 
          = methgen.getReturnType();
                  
          //        methgen.addLocalVariable(name, type, slot, start, end)
                  
                  Type[] types 
          = methgen.getArgumentTypes();
                  
          int slot = methgen.isStatic()?0:1;//非靜態(tài)方法slot 0處應(yīng)該存儲(chǔ)的是this
                  //// 這種方式與Java如何處理方法調(diào)用有關(guān)。對(duì)于非靜態(tài)的方法,每次調(diào)用的第一個(gè)(隱藏的)參數(shù)是目標(biāo)對(duì)象的this引用(就是位置0儲(chǔ)存的內(nèi)容)。
                  for(int i = 0;i<types.length;i++){
                      slot 
          += types[i].getSize();//long,double的size為2
                  }

                  
                  
          //save time prior to invocation
                  
          //createInvoke在常量池增加了 addMethodref,并且addMethodref方法會(huì)先在常量池中查找是否有這個(gè)方法存在,沒有則創(chuàng)建一系列的與此方法相關(guān)的常量池內(nèi)容
                  
          //看看這個(gè)方法是怎么實(shí)現(xiàn)的,為什么此方法中INVOKEINTERFACE的要有nargs
                  
          //InstructionFactory的實(shí)例方法一般要用到cp在常量池中添加引用,其靜態(tài)的方法一般只是創(chuàng)建一些指令,而這些指令不需要在常量池添加內(nèi)容
                  
          //INVOKEXXXXX指令包括一個(gè)index指示此方法在常量池中的索引
                  //// 調(diào)用靜態(tài)的long java.lang.System.currentTimeMillis()方法,調(diào)用結(jié)束后函數(shù)的返回的long類型的值會(huì)壓入operand stack操作數(shù)堆棧
                  ilist.append(ifact.createInvoke("java.lang.System""currentTimeMillis"
                          Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC));
          //currentTimemillis()的方法結(jié)果在operand stack棧頂
                  
                  
          //createStore方法生成了XSTORE指令,彈出operand stack棧頂?shù)脑貙懭氲侥硞€(gè)局部變量中,
                  
          //參照之前打印出的局部變量的信息可以知道若是實(shí)例方法則 index=0處保留的this,之后是用到的方法參數(shù)的index,然后是方法內(nèi)定義的局部變量
                  
          //slot標(biāo)記在局部變量中的位置,
                  
          //這個(gè)局部變量沒有設(shè)置名稱????????
                  ilist.append(InstructionFactory.createStore(Type.LONG, slot));
                  
                  
          //call the wrapped method
                  int offset =0;
                  
          short invoke = Constants.INVOKESTATIC;
                  
          //如果是實(shí)例方法則load this到棧中
                  if(!methgen.isStatic()){
                      
          //// 如果不是調(diào)用靜態(tài)函數(shù),將調(diào)用的第一個(gè)(隱藏的)參數(shù)(目標(biāo)對(duì)象的this引用)壓入operand stack
                      ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));
                      offset 
          =1;
                      invoke 
          = Constants.INVOKESPECIAL;
                  }

                  
          //load 參數(shù)到棧中
                  for(int i=0;i<types.length;i++){
                      Type type 
          = types[i];
                      ilist.append(InstructionFactory.createLoad(type, offset));
          // 按參數(shù)類型把參數(shù)一個(gè)個(gè)從本地變量堆棧取出,壓入operand stack
                      
          //Long Double的size為2,void為0,其他的為1
                      offset += type.getSize();
                  }

                  
                  
          //執(zhí)行方法buildString$impl()
                  ilist.append(ifact.createInvoke(cname, iname, 
                          returnType, types, invoke));
          //消耗oprand stack的this參數(shù)和length參數(shù)
                                                      
          //并將結(jié)果保存在操作數(shù)的棧頂
                  
                  
          //stor result for return later
                  if(returnType != Type.VOID){
                      
          //+2是因?yàn)橹凹拥牡膌ong局部變量占兩個(gè)2個(gè)字,這個(gè)字是虛擬機(jī)定義的,一般為32位
                      //// 將名為iname的函數(shù)返回值復(fù)制到本地變量堆棧的slot+2的位置上
                      ilist.append(InstructionFactory.createStore(returnType,slot+2));
                  }

                  
                  
          //print time required for method call
                  
          //createFieldAccess中的 addFieldref方法先在ConstantFieldref常量池中根據(jù)type的描述符創(chuàng)建引用
                  
          //然后根據(jù)kind來創(chuàng)建是GETFIELD,PUTFIELD,GETSTATIC,PUTSTATIC哪個(gè)指令
                  //// 獲取靜態(tài)對(duì)象java.lang.System.out的引用,返回值壓入operand stack
                  ilist.append(ifact.createFieldAccess("java.lang.System"
                          , 
          "out"new ObjectType("java.io.PrintStream"), 
                          Constants.GETSTATIC));
          //out會(huì)在棧頂
                  
                  
          //ilist.append(InstructionFactory.createDup(1));
                  ilist.append(InstructionConstants.DUP);//復(fù)制棧頂元素out
                  ilist.append(InstructionConstants.DUP);//在復(fù)制,當(dāng)前棧頂前三元素都為out引用,供下面的三次print使用out引用
                  
                  String text 
          = "Call to method "+methgen.getName()+" took ";
                  
          //實(shí)際還是調(diào)的new LDC
                  ilist.append(new PUSH(pgen,text));
                  
                  ilist.append(ifact.createInvoke(
          "java.io.PrintStream"
                          
          "print", Type.VOID, new Type[]{Type.STRING}
                          Constants.INVOKEVIRTUAL));
          //消耗調(diào)一個(gè)out和棧頂?shù)囊粋€(gè)元素
                                                   
          // 調(diào)用結(jié)束,operand stack彈出一個(gè)String的引用和一個(gè)out的引用(還剩2個(gè)out),函數(shù)沒有返回值
                  
                  ilist.append(ifact.createInvoke(
          "java.lang.System"
                          
          "currentTimeMillis", Type.LONG, Type.NO_ARGS, 
                          Constants.INVOKESTATIC));
          //operand stack棧頂保留此方法的結(jié)果,即結(jié)束時(shí)間
                                                   
          //調(diào)用java.lang.System.currentTimeMillis()方法,調(diào)用結(jié)束后函數(shù)的返回的long類型的值會(huì)壓入堆棧operand 
                  
                  
          //load 局部變量到棧頂
                  
          //從本地變量堆棧的slot位置載入先前儲(chǔ)存的long值,壓入operand stack
                  ilist.append(InstructionFactory.createLoad(Type.LONG, slot));
                  
                  
          //棧頂兩個(gè)元素進(jìn)行減法操作,結(jié)果保存在棧頂
                  
          // 調(diào)用long的減法指令,彈出2個(gè)long值,并把結(jié)果壓入operand stack,現(xiàn)在operand stack的top第一個(gè)是long,第二個(gè)是out的引用
                  ilist.append(InstructionConstants.LSUB);
                  
                  ilist.append(ifact.createInvoke(
          "java.io.PrintStream"
                          
          "print", Type.VOID, new Type[]{Type.LONG}
                          Constants.INVOKEVIRTUAL));
          //消耗一個(gè)out,和減法的結(jié)果
                  
                  
          // 將String對(duì)象" ms."放入pgen,并把其在pgen的引用(這個(gè)引用其實(shí)是字符串在常量池中的索引下標(biāo))壓入operand stack(供out.print(Sting)調(diào)用的參數(shù))
                  ilist.append(new PUSH(pgen," ms."));//常量入棧,首先會(huì)判斷常量池中是否有此字符串
                  ilist.append(ifact.createInvoke("java.io.PrintStream"
                          
          "println", Type.VOID, new Type[]{Type.STRING}
                          Constants.INVOKEVIRTUAL));
          //消耗調(diào)最后一個(gè)out和剛?cè)霔5? ms."
                  
                  
          //如果返回類型不為void,則將返回結(jié)果入棧并返回
                  if(returnType != Type.VOID){
                      
          //處理返回值,如果不為空,從本地局部對(duì)象堆棧的slot+2位置讀取指定類型的返回值壓入operand stack
                      ilist.append(InstructionFactory.createLoad(returnType, slot+2));
                  }

                  
                  ilist.append(InstructionFactory.createReturn(returnType));
          //根據(jù)相應(yīng)的返回類型創(chuàng)建相應(yīng)的返回指令
                  
                  
                  
          //finalize the construted method
                  wrapgen.stripAttributes(true);
                  wrapgen.setMaxStack();
                  wrapgen.setMaxLocals();
                  cgen.addMethod(wrapgen.getMethod());
                  ilist.dispose();
                  
                  
                  
                  
                  
          /*
                   * ifact.createPrintln(s)
                   * 
                   *     public InstructionList createPrintln( String s ) {
                  InstructionList il = new InstructionList();
                  int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
                  int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
                  il.append(new GETSTATIC(out));
                  il.append(new PUSH(cp, s));
                  il.append(new INVOKEVIRTUAL(println));
                  return il;
              }
                   
          */

                  
                  
              }


              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args) {
                  
                  args[
          0]="D:\\java to eclipse\\javaeclipsestudy\\workspace\\BCELTest\\bin\\StringBuilder.class";
                  args[
          1]="buildString";
                  String targetClassfile 
          = "StringBuilder.class";
                  
          if(args.length==2 && args[0].endsWith(".class")){
                      
          try{
                          JavaClass jclas 
          = new ClassParser(args[0]).parse();
                          
                          ClassGen cgen 
          = new ClassGen(jclas);
                          Method[] methods 
          = jclas.getMethods();
                          
                          
          int index;
                          
          for(index =0;index<methods.length;index++){
                              
          if(methods[index].getName().equals(args[1])){
                                  
          break;
                              }

                          }

                          
          if(index<methods.length){
                              addWrapper(cgen,methods[index]);
                              FileOutputStream fos 
          = new FileOutputStream(targetClassfile);
                              cgen.getJavaClass().dump(fos);
                              fos.close();
                          }
          else{
                              System.err.println(
          "Method " + args[1]+"not found in"+ args[0]);
                          }

                      }
          catch(Exception e){
                          e.printStackTrace();
                      }

                  }
          else{
                      System.out.println(
          "usage: class-file method-name");
                  }


              }


          }




          public class StringBuilder
          {
              
          private String buildString$impl(int length) {
                  String result 
          = "";
                  
          for (int i = 0; i < length; i++{
                      result 
          += (char)(i%26 + 'a');
                  }

                  
          return result;
              }

              
              
          private String buildString(int length) {
                  
          long start = System.currentTimeMillis();
                  String result 
          = buildString$impl(length);
                  System.out.println(
          "Call to buildString$impl took " +
                      (System.currentTimeMillis()
          -start) + " ms.");
                  
          return result;
              }

              
              
          public static void main(String[] argv) {
                  StringBuilder inst 
          = new StringBuilder();
                  
          for (int i = 0; i < argv.length; i++{
                      String result 
          = inst.buildString(Integer.parseInt(argv[i]));
                      System.out.println(
          "Constructed string of length " +
                          result.length());
                  }

              }

          }



          字節(jié)碼
          --------------------------------33
          --------------------------------33
          0
          2
          CONSTANT_Utf8[
          1]("SourceFile")
          true
          CONSTANT_Utf8[
          1]("StringBuilder.java")
          1
          StringBuilder.java
          StringBuilder.java
          ---------------------------------------------------------------------------
          1:CONSTANT_Class[7](name_index = 2)
          2:CONSTANT_Utf8[1]("StringBuilder")
          3:CONSTANT_Class[7](name_index = 4)
          4:CONSTANT_Utf8[1]("java/lang/Object")
          5:CONSTANT_Utf8[1]("<init>")
          6:CONSTANT_Utf8[1]("()V")
          7:CONSTANT_Utf8[1]("Code")
          8:CONSTANT_Methodref[10](class_index = 3, name_and_type_index = 9)
          9:CONSTANT_NameAndType[12](name_index = 5, signature_index = 6)
          10:CONSTANT_Utf8[1]("LineNumberTable")
          11:CONSTANT_Utf8[1]("LocalVariableTable")
          12:CONSTANT_Utf8[1]("this")
          13:CONSTANT_Utf8[1]("LStringBuilder;")
          14:CONSTANT_Utf8[1]("buildString$impl")
          15:CONSTANT_Utf8[1]("(I)Ljava/lang/String;")
          16:CONSTANT_String[8](string_index = 17)
          17:CONSTANT_Utf8[1]("")
          18:CONSTANT_Class[7](name_index = 19)
          19:CONSTANT_Utf8[1]("java/lang/StringBuilder")
          20:CONSTANT_Methodref[10](class_index = 21, name_and_type_index = 23)
          21:CONSTANT_Class[7](name_index = 22)
          22:CONSTANT_Utf8[1]("java/lang/String")
          23:CONSTANT_NameAndType[12](name_index = 24, signature_index = 25)
          24:CONSTANT_Utf8[1]("valueOf")
          25:CONSTANT_Utf8[1]("(Ljava/lang/Object;)Ljava/lang/String;")
          26:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 27)
          27:CONSTANT_NameAndType[12](name_index = 5, signature_index = 28)
          28:CONSTANT_Utf8[1]("(Ljava/lang/String;)V")
          29:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 30)
          30:CONSTANT_NameAndType[12](name_index = 31, signature_index = 32)
          31:CONSTANT_Utf8[1]("append")
          32:CONSTANT_Utf8[1]("(C)Ljava/lang/StringBuilder;")
          33:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 34)
          34:CONSTANT_NameAndType[12](name_index = 35, signature_index = 36)
          35:CONSTANT_Utf8[1]("toString")
          36:CONSTANT_Utf8[1]("()Ljava/lang/String;")
          37:CONSTANT_Utf8[1]("length")
          38:CONSTANT_Utf8[1]("I")
          39:CONSTANT_Utf8[1]("result")
          40:CONSTANT_Utf8[1]("Ljava/lang/String;")
          41:CONSTANT_Utf8[1]("i")
          42:CONSTANT_Utf8[1]("buildString")
          43:CONSTANT_Methodref[10](class_index = 44, name_and_type_index = 46)
          44:CONSTANT_Class[7](name_index = 45)
          45:CONSTANT_Utf8[1]("java/lang/System")
          46:CONSTANT_NameAndType[12](name_index = 47, signature_index = 48)
          47:CONSTANT_Utf8[1]("currentTimeMillis")
          48:CONSTANT_Utf8[1]("()J")
          49:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 50)
          50:CONSTANT_NameAndType[12](name_index = 14, signature_index = 15)
          51:CONSTANT_Fieldref[9](class_index = 44, name_and_type_index = 52)
          **********************************************************************
          cc.toString : CONSTANT_Class[
          7](name_index = 45)
          java
          /lang/System
          cnat.toString : CONSTANT_NameAndType[
          12](name_index = 53, signature_index = 54)
          out
          Ljava
          /io/PrintStream;
          **********************************************************************
          52:CONSTANT_NameAndType[12](name_index = 53, signature_index = 54)
          53:CONSTANT_Utf8[1]("out")
          54:CONSTANT_Utf8[1]("Ljava/io/PrintStream;")
          55:CONSTANT_String[8](string_index = 56)
          56:CONSTANT_Utf8[1]("Call to buildString$impl took ")
          57:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 58)
          58:CONSTANT_NameAndType[12](name_index = 31, signature_index = 59)
          59:CONSTANT_Utf8[1]("(J)Ljava/lang/StringBuilder;")
          60:CONSTANT_String[8](string_index = 61)
          61:CONSTANT_Utf8[1](" ms.")
          62:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 63)
          63:CONSTANT_NameAndType[12](name_index = 31, signature_index = 64)
          64:CONSTANT_Utf8[1]("(Ljava/lang/String;)Ljava/lang/StringBuilder;")
          65:CONSTANT_Methodref[10](class_index = 66, name_and_type_index = 68)
          66:CONSTANT_Class[7](name_index = 67)
          67:CONSTANT_Utf8[1]("java/io/PrintStream")
          68:CONSTANT_NameAndType[12](name_index = 69, signature_index = 28)
          69:CONSTANT_Utf8[1]("println")
          70:CONSTANT_Utf8[1]("start")
          71:CONSTANT_Utf8[1]("J")
          72:CONSTANT_Utf8[1]("main")
          73:CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
          74:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 9)
          75:CONSTANT_Methodref[10](class_index = 76, name_and_type_index = 78)
          76:CONSTANT_Class[7](name_index = 77)
          77:CONSTANT_Utf8[1]("java/lang/Integer")
          78:CONSTANT_NameAndType[12](name_index = 79, signature_index = 80)
          79:CONSTANT_Utf8[1]("parseInt")
          80:CONSTANT_Utf8[1]("(Ljava/lang/String;)I")
          81:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 82)
          82:CONSTANT_NameAndType[12](name_index = 42, signature_index = 15)
          83:CONSTANT_String[8](string_index = 84)
          84:CONSTANT_Utf8[1]("Constructed string of length ")
          85:CONSTANT_Methodref[10](class_index = 21, name_and_type_index = 86)
          86:CONSTANT_NameAndType[12](name_index = 37, signature_index = 87)
          87:CONSTANT_Utf8[1]("()I")
          88:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 89)
          89:CONSTANT_NameAndType[12](name_index = 31, signature_index = 90)
          90:CONSTANT_Utf8[1]("(I)Ljava/lang/StringBuilder;")
          91:CONSTANT_Utf8[1]("argv")
          92:CONSTANT_Utf8[1]("[Ljava/lang/String;")
          93:CONSTANT_Utf8[1]("inst")
          94:CONSTANT_Utf8[1]("SourceFile")
          95:CONSTANT_Utf8[1]("StringBuilder.java")
          ------------------------------------------------------
          ------------------------------------------------------
          start method method method
          -----------------------------------
          方法訪問標(biāo)志
          1
          方法訪問名稱
          me[i].getName()  
          <init>
          CONSTANT_Utf8[
          1]("<init>")
          方法簽名
          ()V
          CONSTANT_Utf8[
          1]("()V")
          方法的參數(shù)類型
          [Lorg.apache.bcel.generic.Type;@54172f
          方法的返回類型
          void
          方法的Code
          public void <init>()
          Code(max_stack 
          = 1, max_locals = 1, code_length = 5)
          0:    aload_0
          1:    invokespecial    java.lang.Object.<init> ()V (8)
          4:    return

          Attribute(s) 
          = 
          LineNumber(
          02)
          LocalVariable(start_pc 
          = 0, length = 5, index = 0:StringBuilder this)

          end method method method
          -----------------------------------
          start method method method
          -----------------------------------
          方法訪問標(biāo)志
          2
          方法訪問名稱
          me[i].getName()  buildString$impl
          CONSTANT_Utf8[
          1]("buildString$impl")
          方法簽名
          (I)Ljava
          /lang/String;
          CONSTANT_Utf8[
          1]("(I)Ljava/lang/String;")
          方法的參數(shù)類型
          [Lorg.apache.bcel.generic.Type;@1ed2ae8
          方法的返回類型
          java.lang.String
          方法的Code
          private String buildString$impl(int length)
          Code(max_stack 
          = 3, max_locals = 4, code_length = 44)
          0:    ldc        "" (16)
          2:    astore_2
          3:    iconst_0
          4:    istore_3
          5:    goto        #37
          8:    new        <java.lang.StringBuilder> (18)
          11:   dup
          12:   aload_2
          13:   invokestatic    java.lang.String.valueOf (Ljava/lang/Object;)Ljava/lang/String; (20)
          16:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
          19:   iload_3
          20:   bipush        26
          22:   irem
          23:   bipush        97
          25:   iadd
          26:   i2c
          27:   invokevirtual    java.lang.StringBuilder.append (C)Ljava/lang/StringBuilder; (29)
          30:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
          33:   astore_2
          34:   iinc        %3    1
          37:   iload_3
          38:   iload_1
          39:   if_icmplt        #8
          42:   aload_2
          43:   areturn

          Attribute(s) 
          = 
          LineNumber(
          05), LineNumber(36), LineNumber(87), LineNumber(346), 
          LineNumber(
          429)
          LocalVariable(start_pc 
          = 0, length = 44, index = 0:StringBuilder this)
          LocalVariable(start_pc 
          = 0, length = 44, index = 1:int length)
          LocalVariable(start_pc 
          = 3, length = 41, index = 2:String result)
          LocalVariable(start_pc 
          = 5, length = 37, index = 3:int i)

          end method method method
          -----------------------------------
          start method method method
          -----------------------------------
          方法訪問標(biāo)志
          2
          方法訪問名稱
          me[i].getName()  buildString
          CONSTANT_Utf8[
          1]("buildString")
          方法簽名
          (I)Ljava
          /lang/String;
          CONSTANT_Utf8[
          1]("(I)Ljava/lang/String;")
          方法的參數(shù)類型
          [Lorg.apache.bcel.generic.Type;@19c26f5
          方法的返回類型
          java.lang.String
          方法的Code
          private String buildString(int length)
          Code(max_stack 
          = 6, max_locals = 5, code_length = 45)
          0:    invokestatic    java.lang.System.currentTimeMillis ()J (43)
          3:    lstore_2
          4:    aload_0
          5:    iload_1
          6:    invokespecial    StringBuilder.buildString$impl (I)Ljava/lang/String; (49)
          9:    astore        %4
          11:   getstatic        java.lang.System.out Ljava/io/PrintStream; (51)
          14:   new        <java.lang.StringBuilder> (18)
          17:   dup
          18:   ldc        "Call to buildString$impl took " (55)
          20:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
          23:   invokestatic    java.lang.System.currentTimeMillis ()J (43)
          26:   lload_2
          27:   lsub
          28:   invokevirtual    java.lang.StringBuilder.append (J)Ljava/lang/StringBuilder; (57)
          31:   ldc        " ms." (60)
          33:   invokevirtual    java.lang.StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; (62)
          36:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
          39:   invokevirtual    java.io.PrintStream.println (Ljava/lang/String;)V (65)
          42:   aload        %4
          44:   areturn

          Attribute(s) 
          = 
          LineNumber(
          013), LineNumber(414), LineNumber(1115), LineNumber(2316), 
          LineNumber(
          3915), LineNumber(4217)
          LocalVariable(start_pc 
          = 0, length = 45, index = 0:StringBuilder this)
          LocalVariable(start_pc 
          = 0, length = 45, index = 1:int length)
          LocalVariable(start_pc 
          = 4, length = 41, index = 2:long start)
          LocalVariable(start_pc 
          = 11, length = 34, index = 4:String result)

          end method method method
          -----------------------------------
          start method method method
          -----------------------------------
          方法訪問標(biāo)志
          9
          方法訪問名稱
          me[i].getName()  main
          CONSTANT_Utf8[
          1]("main")
          方法簽名
          ([Ljava
          /lang/String;)V
          CONSTANT_Utf8[
          1]("([Ljava/lang/String;)V")
          方法的參數(shù)類型
          [Lorg.apache.bcel.generic.Type;@c1b531
          方法的返回類型
          void
          方法的Code
          public static void main(String[] argv)
          Code(max_stack 
          = 4, max_locals = 4, code_length = 59)
          0:    new        <StringBuilder> (1)
          3:    dup
          4:    invokespecial    StringBuilder.<init> ()V (74)
          7:    astore_1
          8:    iconst_0
          9:    istore_2
          10:   goto        #52
          13:   aload_1
          14:   aload_0
          15:   iload_2
          16:   aaload
          17:   invokestatic    java.lang.Integer.parseInt (Ljava/lang/String;)I (75)
          20:   invokespecial    StringBuilder.buildString (I)Ljava/lang/String; (81)
          23:   astore_3
          24:   getstatic        java.lang.System.out Ljava/io/PrintStream; (51)
          27:   new        <java.lang.StringBuilder> (18)
          30:   dup
          31:   ldc        "Constructed string of length " (83)
          33:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
          36:   aload_3
          37:   invokevirtual    java.lang.String.length ()I (85)
          40:   invokevirtual    java.lang.StringBuilder.append (I)Ljava/lang/StringBuilder; (88)
          43:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
          46:   invokevirtual    java.io.PrintStream.println (Ljava/lang/String;)V (65)
          49:   iinc        %2    1
          52:   iload_2
          53:   aload_0
          54:   arraylength
          55:   if_icmplt        #13
          58:   return

          Attribute(s) 
          = 
          LineNumber(
          021), LineNumber(822), LineNumber(1323), LineNumber(2424), 
          LineNumber(
          3625), LineNumber(4624), LineNumber(4922), LineNumber(5827)

          LocalVariable(start_pc 
          = 0, length = 59, index = 0:String[] argv)
          LocalVariable(start_pc 
          = 8, length = 51, index = 1:StringBuilder inst)
          LocalVariable(start_pc 
          = 10, length = 48, index = 2:int i)
          LocalVariable(start_pc 
          = 24, length = 25, index = 3:String result)

          end method method method
          -----------------------------------

          posted on 2009-08-13 15:58 Frank_Fang 閱讀(1395) 評(píng)論(7)  編輯  收藏 所屬分類: bcel javassist

          評(píng)論:
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-13 16:13 | Frank_Fang
          Java虛擬機(jī)框架(frame)翻譯為幀是不是更貼切些
          用于存儲(chǔ)數(shù)據(jù)和部分結(jié)果,以及進(jìn)行動(dòng)態(tài)鏈接,返回方法的值和調(diào)度異常
          每次Java方法被調(diào)用時(shí)創(chuàng)建一個(gè)新的frame,當(dāng)frame的方法結(jié)束時(shí),不論正常的,還是不正常的結(jié)束(通過拋出一個(gè)異常)框架從創(chuàng)建該框架的線程的Java棧分配,每個(gè)frame有它自己的局部變量集,和自己的操作數(shù)棧,這些結(jié)構(gòu)的存儲(chǔ)器空間可以同時(shí)分配,因?yàn)榫植孔兞繀^(qū)和操作數(shù)棧的大小是編譯期已知的。

          總的來說要把方法的局部變量集搞清楚,以及方法的操作數(shù)棧的當(dāng)前狀態(tài)搞清楚,以及每個(gè)jvm指令會(huì)對(duì)棧產(chǎn)生什么影響搞清楚。
          下一步在仔細(xì)研究一下修改class文件的其他東西。  回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-13 16:15 | Frank_Fang
          也可以看出String s = s+"ddd";時(shí)采用的是java.lang.StringBuilder來進(jìn)行操作的
          以及對(duì)于String s="abc" 與String s = new String("abc")這個(gè)字符串常量池就很清楚了  回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-13 18:43 | Frank_Fang
          public class AASTOREextends ArrayInstructionimplements StackConsumerAASTORE - Store into reference array

          Stack: ..., arrayref, index, value -> ...


          public class AALOADextends ArrayInstructionimplements StackProducerAALOAD - Load reference from array

          <red>Stack: ..., arrayref, index -> value</red>  回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-13 19:54 | Frank_Fang
          private String buildString(int)

          Attributes
          Code
          Byte
          offset Instruction Argument
          0 invokestatic System.currentTimeMillis ()J():long
          3 lstore_2
          4 aload_0
          5 iload_1
          6 invokespecial StringBuilder.buildString$impl (I)Ljava/lang/String;(int):String
          9 astore %4
          11 getstatic System.out Ljava/io/PrintStream;
          14 dup
          15 dup
          16 ldc "Call to method buildString$impl took "
          18 invokevirtual java.io.PrintStream.print (Ljava/lang/String;)V(String):void
          21 invokestatic System.currentTimeMillis ()J():long
          24 lload_2
          25 lsub
          26 invokevirtual java.io.PrintStream.print (J)V(long):void
          29 ldc " ms."
          31 invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V(String):void
          34 aload %4
          36 areturn


          實(shí)際生成的字節(jié)碼中沒有方法的Code屬性的LocalVariableTable
          LineNumberTable 信息
            回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼[未登錄] 2009-08-14 23:55 | alex
          實(shí)際生成的字節(jié)碼中沒有方法的Code屬性的LocalVariableTable
          LineNumberTable 信息 ???
          這個(gè)為什么沒有這些信息了?不知道你想過沒有???
            回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-15 00:17 | Frank_Fang
          @alex
          這個(gè)我現(xiàn)在還不太清楚
          wrapgen.stripAttributes(true);
          這個(gè)好像設(shè)置成false是生成lineNumber和Localvariabel Attribute的信息
          但是我設(shè)置成false之后,允許生成的代碼就報(bào)錯(cuò)誤了
          Exception in thread "main" java.lang.ClassFormatError: Invalid length 44 in Loca
          lVariableTable in class file StringBuilder
          at java.lang.ClassLoader.defineClass1(Native Method)
          at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
          at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
          4)
          at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
          at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
          at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
          at java.security.AccessController.doPrivileged(Native Method)
          at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
          at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
          at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
          Could not find the main class: StringBuilder. Program will exit.


            回復(fù)  更多評(píng)論
            
          # re: 用 BCEL 設(shè)計(jì)字節(jié)碼 2009-08-15 19:58 | Frank_Fang
          @alex
          把stripAtrribute設(shè)置成false后,即新的方法生成linenumber和localvariable屬性

          這是原先的屬性信息
          private String buildString$impl(int length)
          Code(max_stack = 3, max_locals = 4, code_length = 51)
          0: ldc "" (16)
          2: astore_2
          3: iconst_0
          4: istore_3
          5: goto #37
          8: new <java.lang.StringBuilder> (18)
          11: dup
          12: aload_2
          13: invokestatic java.lang.String.valueOf (Ljava/lang/Object;)Ljava/lang/String; (20)
          16: invokespecial java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
          19: iload_3
          20: bipush 26
          22: irem
          23: bipush 97
          25: iadd
          26: i2c
          27: invokevirtual java.lang.StringBuilder.append (C)Ljava/lang/StringBuilder; (29)
          30: invokevirtual java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
          33: astore_2
          34: iinc %3 1
          37: iload_3
          38: iload_1
          39: if_icmplt #8
          42: getstatic java.lang.System.out Ljava/io/PrintStream; (37)
          45: aload_2
          46: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (43)
          49: aload_2
          50: areturn

          Attribute(s) =
          LocalVariable(start_pc = 0, length = 51, index = 0:StringBuilder this)
          LocalVariable(start_pc = 0, length = 51, index = 1:int length)
          LocalVariable(start_pc = 3, length = 48, index = 2:String result)
          LocalVariable(start_pc = 5, length = 40, index = 3:int i)
          LineNumber(0, 6), LineNumber(3, 7), LineNumber(8, 8), LineNumber(34, 7),
          LineNumber(42, 10), LineNumber(49, 12)


          --------------------------------------------------------
          完整的code.toString的信息
          private String buildString(int length)
          Code(max_stack = 6, max_locals = 5, code_length = 37)
          0: invokestatic java.lang.System.currentTimeMillis ()J (81)
          3: lstore_2
          4: aload_0
          5: iload_1
          6: invokespecial StringBuilder.buildString$impl (I)Ljava/lang/String; (83)
          9: astore %4
          11: getstatic java.lang.System.out Ljava/io/PrintStream; (37)
          14: dup
          15: dup
          16: ldc "Call to method buildString$impl took " (85)
          18: invokevirtual java.io.PrintStream.print (Ljava/lang/String;)V (88)
          21: invokestatic java.lang.System.currentTimeMillis ()J (81)
          24: lload_2
          25: lsub
          26: invokevirtual java.io.PrintStream.print (J)V (91)
          29: ldc " ms." (93)
          31: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (43)
          34: aload %4
          36: areturn

          Attribute(s) =
          LocalVariable(start_pc = 0, length = 51, index = 0:StringBuilder this)
          LocalVariable(start_pc = 0, length = 51, index = 1:int length)
          LocalVariable(start_pc = 3, length = 48, index = 2:String result)
          LocalVariable(start_pc = 5, length = 40, index = 3:int i)
          LineNumber(0, 6), LineNumber(3, 7), LineNumber(8, 8), LineNumber(34, 7),
          LineNumber(42, 10), LineNumber(49, 12)

          end method method method-----------------------------------
          這個(gè)屬性信息使用還是使用的原先方法的,顯然length=55超過了指令的長度
          36,執(zhí)行時(shí)會(huì)檢查類的局部變量屬性信息發(fā)現(xiàn)不正確就報(bào)錯(cuò)了

          這兩個(gè)屬性的信息應(yīng)該是用來調(diào)試器來使用的,可以自己在字節(jié)碼文件中自己添加這些信息,不過自己添加比較麻煩.
          不過我另外一個(gè)程序的方法也自己生成了屬性信息,這些屬性信息也改變了,但是改變的不正確,但是程序能夠執(zhí)行。。

          這中的原因我現(xiàn)在也搞不清楚了。

            回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 富蕴县| 嘉兴市| 衡水市| 大渡口区| 郧西县| 昌宁县| 永德县| 元谋县| 德江县| 昌吉市| 屏山县| 谢通门县| 老河口市| 化州市| 尼木县| 穆棱市| 高唐县| 财经| 马山县| 吉林省| 铜梁县| 祁连县| 双峰县| 昆明市| 台东市| 松江区| 衡阳市| 民勤县| 东至县| 潜江市| 天柱县| 连山| 沙雅县| 余江县| 高安市| 翁牛特旗| 武隆县| 泸溪县| 华容县| 安图县| 四子王旗|