程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 用BCEL設計字節碼 - 直接在原方法上加指令

用BCEL設計字節碼 - 直接在原方法上加指令

編輯:關於JAVA

前一個是直接生成了一個一個方法對原方法進行調用,現在直接在原方法上進行修改

即將

public class StringBuilder
{
     private String buildString(int length) {
         String result = "";
         for (int i = 0; i < length; i++) {
             result += (char)(i%26 + 'a');
         }
         System.out.println(result);
         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());
         }
     }
}

改成:

public class StringBuilder
{
     private String buildString(int length) {

         System.out.println("start start start");
         long starttime = System.currentTimeMillis();

         String result = "";
         for (int i = 0; i < length; i++) {
             result += (char)(i%26 + 'a');
         }
         System.out.println(result);

         System.out.println("Call to buildString$impl took " +
                 (System.currentTimeMillis()-starttime) + " ms.");
         System.out.println("end end end end");

         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());
         }
     }
}

修改代碼如下:

import java.io.FileOutputStream;
import java.util.Iterator;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LineNumberTable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.LocalVariableGen;
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 BCELTiming2 {

     private static void modifyWrapper(ClassGen cgen,Method method){

         InstructionFactory ifact = new InstructionFactory(cgen);
         ConstantPoolGen pgen = cgen.getConstantPool();

         String cname = cgen.getClassName();

         MethodGen wrapgen = new MethodGen(method,cname,pgen);

         //除掉這個原來的方法
         cgen.removeMethod(method);

         System.out.println("打印出這個方法看看---------------------------------start");
         System.out.println(wrapgen.toString());
         System.out.println("打印出這個方法看看---------------------------------end");

         InstructionList ilist = wrapgen.getInstructionList();
         System.out.println("看看這個方法的InstructionList-----------------------------start");
         System.out.println(ilist.toString());
         System.out.println("看看這個方法的InstructionList-----------------------------start");

         System.out.println("看看這個方法InstructionList的各個InstructionHandle的信息--------------------start");
         Iterator handleIt = ilist.iterator();

         while(handleIt.hasNext()){
             InstructionHandle iHandle = (InstructionHandle)handleIt.next();
             System.out.println(iHandle.getAttributes());
             System.out.println(iHandle.toString());
         }

         System.out.println("看看這個方法InstructionList的各個InstructionHandle的信息--------------------end");

         System.out.println("先看看此方法的LocalVariableTable的信息--------------------------------------start");
         LocalVariableTable lvt = wrapgen.getLocalVariableTable(pgen);
         System.out.println(lvt.toString());
         System.out.println("先看看此方法的LocalVariableTable的信息--------------------------------------end");

         LineNumberTable lnt = wrapgen.getLineNumberTable(pgen);
         System.out.println("LineNumberTable--------------------------------------start");
         System.out.println(lnt.toString());
         System.out.println("LineNumberTable--------------------------------------end");

         Type returnType = wrapgen.getReturnType();

         Type[] types = wrapgen.getArgumentTypes();
         int slot = wrapgen.isStatic()?0:1;//非靜態方法slot 0處應該存儲的是this
         //// 這種方式與Java如何處理方法調用有關。對於非靜態的方法,每次調用的第一個(隱藏的)參數是目標對象的this引用(就是位置0儲存的內容)。
         for(int i = 0;i<types.length;i++){
             slot += types[i].getSize();//long,double的size為2
         }

         /**//*
          * 判斷原來的方法用到了哪些局部變量,獲得局部變量中已經用到的最大索引
          * 將新產生的局部變量加到最大索引後,本來准備自己寫的
          * BCEL中已經這樣的方法了
          */

         LocalVariableGen lvg = wrapgen.addLocalVariable("starttime", Type.LONG, null, null);

         //先插入一條打印語句不使用局部變量
         InstructionList printlnList = ifact.createPrintln("start test start test start test start test");

         InvokeInstruction invokestatic = ifact.createInvoke("java.lang.System",
                 "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC);

         InstructionHandle firstHandle = printlnList.append(invokestatic);
         //這個會不會將局部變量為2的地方的局部變量給覆蓋,然後此局部變量也沒有定義名字??slot這個index怎麼來確定
         //slot現在應該為2,之前代碼塊放的是result信息是aload,
         //寫到新產生的局部變量的索引處
         printlnList.append(InstructionFactory.createStore(Type.LONG, lvg.getIndex()));

         //加入到之前的inlist中
         ilist.insert(printlnList);

         //

         //在語句最後在打印結束語句,不能簡單插入在最後面,加入方法有返回值,則要插入在return 之前
         //在return的時候,還要先將return的引用加入到操作數棧,怎麼獲取result在局部變量中index
         InstructionHandle insertposition =null;
         if(returnType.getType()!=Type.VOID.getType()){
             insertposition = ilist.getEnd().getPrev();

         }else{
             //返回值為Type.void的話,由於沒有返回值,因此只需要在return指令前加就夠了,往前取一個即可
             insertposition = ilist.getEnd();
         }
         InstructionList tempList = new InstructionList();
         tempList.append(ifact.createFieldAccess("java.lang.System"
                 , "out", new ObjectType("java.io.PrintStream"),
                 Constants.GETSTATIC));

         tempList.append(InstructionFactory.DUP);
         tempList.append(InstructionFactory.DUP);

         String text = "Call to method "+wrapgen.getName()+" took ";
         tempList.append(new PUSH(pgen,text));
         tempList.append(ifact.createInvoke("java.io.PrintStream",
                 "print", Type.VOID, new Type[]{Type.STRING},
                 Constants.INVOKEVIRTUAL));
         tempList.append(ifact.createInvoke("java.lang.System",
                 "currentTimeMillis", Type.LONG, Type.NO_ARGS,
                 Constants.INVOKESTATIC));
         //獲取之前的的starttime局部變量
         tempList.append(InstructionFactory.createLoad(Type.LONG, lvg.getIndex()));
         tempList.append(InstructionConstants.LSUB);
         tempList.append(ifact.createInvoke("java.io.PrintStream",
                 "print", Type.VOID, new Type[]{Type.LONG},
                 Constants.INVOKEVIRTUAL));
         tempList.append(new PUSH(pgen," ms."));
         tempList.append(ifact.createInvoke("java.io.PrintStream",
                 "println", Type.VOID, new Type[]{Type.STRING},
                 Constants.INVOKEVIRTUAL));

         //在return之前的最後一句是打印end end end.信息
         tempList.append(ifact.createPrintln("end end end end end end end end end end"));

         ilist.insert(insertposition,tempList);



//        LocalVariableGen lvgen  = new LocalVariableGen(slot,"start",Type.LONG,null,null);

         //finalize the construted method
         wrapgen.stripAttributes(false);
         wrapgen.setMaxStack();
         wrapgen.setMaxLocals();
         cgen.addMethod(wrapgen.getMethod());

         System.out.println();
         System.out.println();
         System.out.println(wrapgen.getInstructionList());
         ilist.dispose();

     }


     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){
                     modifyWrapper(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");
         }
     }

}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved