Apache Byte Code Engineering Library (BCEL)简介

官方主页:http://jakarta.apache.org/bcel/index.html

简介:http://www.ibm.com/developerworks/cn/java/j-dyn0414/

以下代码改编(转载)自:http://www.cppblog.com/wmuu/archive/2008/01/04/7947.html

代码如下:

  1. package test;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import org.apache.bcel.Constants;
  5. import org.apache.bcel.classfile.ClassParser;
  6. import org.apache.bcel.classfile.JavaClass;
  7. import org.apache.bcel.classfile.Method;
  8. import org.apache.bcel.generic.ClassGen;
  9. import org.apache.bcel.generic.ConstantPoolGen;
  10. import org.apache.bcel.generic.InstructionConstants;
  11. import org.apache.bcel.generic.InstructionFactory;
  12. import org.apache.bcel.generic.InstructionList;
  13. import org.apache.bcel.generic.MethodGen;
  14. import org.apache.bcel.generic.ObjectType;
  15. import org.apache.bcel.generic.PUSH;
  16. import org.apache.bcel.generic.Type;
  17. public class BcelTest {
  18.     private static void addWrapper(ClassGen cgen, Method method) {
  19.         // set up the construction tools
  20.         InstructionFactory ifact = new InstructionFactory(cgen);
  21.         InstructionList ilist = new InstructionList();
  22.         ConstantPoolGen pgen = cgen.getConstantPool();
  23.         String cname = cgen.getClassName();
  24.         MethodGen wrapgen = new MethodGen(method, cname, pgen);
  25.         wrapgen.setInstructionList(ilist);
  26.         // rename a copy of the original method
  27.         MethodGen methgen = new MethodGen(method, cname, pgen);
  28.         cgen.removeMethod(method);
  29.         String iname = methgen.getName() + "$impl";
  30.         methgen.setName(iname);
  31.         cgen.addMethod(methgen.getMethod());
  32.         //以上是一下初始化的工作
  33.         
  34.         // compute the size of the calling parameters
  35.         // operand stack操作数堆栈
  36.         Type[] types = methgen.getArgumentTypes(); // 取出参数类型数组
  37.         // solt代表本地变量的堆栈偏移量,里头储存了调用methen代表的函数的参数
  38.         int slot = methgen.isStatic() ? 0 : 1// 这种方式与Java如何处理方法调用有关。对于非静态的方法,每次调用的第一个(隐藏的)参数是目标对象的this引用(就是位置0储存的内容)。
  39.         for (int i = 0; i < types.length; i++) {
  40.             slot += types[i].getSize();// 累计个个参数类型的长度,
  41.         }
  42.         // 现在solt指向最后一个参数的下一个位置
  43.         // save time prior to invocation
  44.         // 调用静态的long java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入operand stack操作数堆栈
  45.         ilist.append(ifact.createInvoke("java.lang.System",
  46.                 "currentTimeMillis", Type.LONG, Type.NO_ARGS,
  47.                 Constants.INVOKESTATIC));
  48.         ilist.append(InstructionFactory.createStore(Type.LONG, slot));// 将operand stack的top保存到本地变量堆栈的slot位置,operand stack弹出long值
  49.         // call the wrapped method
  50.         int offset = 0// 偏移量
  51.         short invoke = Constants.INVOKESTATIC; // 预先设置为调用静态函数
  52.         if (!methgen.isStatic()) { // 如果不是调用静态函数,将调用的第一个(隐藏的)参数(目标对象的this引用)压入operand stack
  53.             ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));
  54.             offset = 1;// 偏移量加1
  55.             invoke = Constants.INVOKEVIRTUAL;// 设置为调用非静态函数
  56.         }
  57.         for (int i = 0; i < types.length; i++) { // 遍历所有参数
  58.             Type type = types[i];
  59.             ilist.append(InstructionFactory.createLoad(type, offset)); // 按参数类型把参数一个个从本地变量堆栈取出,压入operand stack
  60.             offset += type.getSize();
  61.         }
  62.         Type result = methgen.getReturnType();// 取得要调用函数的返回值类型
  63.         ilist.append(ifact.createInvoke(cname, iname, result, types, invoke));// 调用方法名为iname的函数
  64.         // store result for return later
  65.         if (result != Type.VOID) {
  66.             ilist.append(InstructionFactory.createStore(result, slot + 2)); // 将名为iname的函数返回值复制到本地变量堆栈的slot+2的位置上
  67.         }
  68.         // print time required for method call
  69.         // 获取静态对象java.lang.System.out的引用,返回值压入operand stack
  70.         ilist.append(ifact.createFieldAccess("java.lang.System""out",
  71.                 new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
  72.         ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。完成后load_stack的头两个元素是静态对象java.lang.System.out的引用
  73.         ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。现在有3个java.lang.System.out的引用。供下面3次调用out.print()函数使用
  74.         String text = "Call to method " + methgen.getName() + " took ";
  75.         ilist.append(new PUSH(pgen, text));// 将text放入pgen(代表常量池),并把其在pgen的引用压入operand stack(供out.print(Sting)调用的参数)
  76.         ilist.append(ifact.createInvoke("java.io.PrintStream""print",
  77.                         Type.VOID, new Type[] { Type.STRING },
  78.                         Constants.INVOKEVIRTUAL));// 调用结束,operand stack弹出一个String的引用和一个out的引用(还剩2个out),函数没有返回值
  79.         ilist.append(ifact.createInvoke("java.lang.System",
  80.                 "currentTimeMillis", Type.LONG, Type.NO_ARGS,
  81.                 Constants.INVOKESTATIC));// 调用java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入堆栈operand stack
  82.         ilist.append(InstructionFactory.createLoad(Type.LONG, slot));// 从本地变量堆栈的slot位置载入先前储存的long值,压入operand stack
  83.         ilist.append(InstructionConstants.LSUB);// 调用long的减法指令,弹出2个long值,并把结果压入operand stack,现在operand stack的top第一个是long,第二个是out的引用
  84.         ilist.append(ifact.createInvoke("java.io.PrintStream""print",
  85.                 Type.VOID, new Type[] { Type.LONG }, Constants.INVOKEVIRTUAL));// 调用out.print(long)方法
  86.         ilist.append(new PUSH(pgen, " ms."));// 将String对象" ms."放入pgen,并把其在pgen的引用压入operand stack(供out.print(Sting)调用的参数)
  87.         ilist
  88.                 .append(ifact.createInvoke("java.io.PrintStream""println",
  89.                         Type.VOID, new Type[] { Type.STRING },
  90.                         Constants.INVOKEVIRTUAL));
  91.         // return result from wrapped method call
  92.         if (result != Type.VOID) {
  93.             ilist.append(InstructionFactory.createLoad(result, slot + 2));// 处理返回值,如果不为空,从本地对象堆栈的slot+2位置读取指定类型的返回值压入operand stack
  94.         }
  95.         ilist.append(InstructionFactory.createReturn(result)); //调用处理返回值的指令,result为返回值的类型
  96.         //下面是一下扫尾工作
  97.         // finalize the constructed method
  98.         wrapgen.stripAttributes(true);
  99.         wrapgen.setMaxStack();
  100.         wrapgen.setMaxLocals();
  101.         cgen.addMethod(wrapgen.getMethod());
  102.         ilist.dispose();
  103.     }
  104.     public static void main(String[] argv) {
  105.         if (argv.length == 2 && argv[0].endsWith(".class")) {
  106.             try {
  107.                 JavaClass jclas = new ClassParser(argv[0]).parse();
  108.                 ClassGen cgen = new ClassGen(jclas);
  109.                 Method[] methods = jclas.getMethods();
  110.                 int index;
  111.                 for (index = 0; index < methods.length; index++) {
  112.                     if (methods[index].getName().equals(argv[1])) {
  113.                         break;
  114.                     }
  115.                 }
  116.                 if (index < methods.length) {
  117.                     addWrapper(cgen, methods[index]);
  118.                     FileOutputStream fos = new FileOutputStream(argv[0]);
  119.                     cgen.getJavaClass().dump(fos);
  120.                     fos.close();
  121.                 } else {
  122.                     System.err.println("Method " + argv[1] + " not found in "
  123.                             + argv[0]);
  124.                 }
  125.             } catch (IOException ex) {
  126.                 ex.printStackTrace(System.err);
  127.             }
  128.         } else {
  129.             System.out.println("Usage: BCELTiming class-file method-name");
  130.         }
  131.     }
  132. }

代码比较难懂,有待日后深入讨论。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值