您的位置:首页 > 运维架构 > Apache

Apache Byte Code Engineering Library (BCEL)简介

2009-01-05 13:35 393 查看
官方主页: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

代码如下:

package test;

import java.io.FileOutputStream;

import java.io.IOException;

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.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 BcelTest {

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

//以上是一下初始化的工作

// compute the size of the calling parameters

// operand stack操作数堆栈

Type[] types = methgen.getArgumentTypes(); // 取出参数类型数组

// solt代表本地变量的堆栈偏移量,里头储存了调用methen代表的函数的参数

int slot = methgen.isStatic() ? 0 : 1; // 这种方式与Java如何处理方法调用有关。对于非静态的方法,每次调用的第一个(隐藏的)参数是目标对象的this引用(就是位置0储存的内容)。

for (int i = 0; i < types.length; i++) {

slot += types[i].getSize();// 累计个个参数类型的长度,

}

// 现在solt指向最后一个参数的下一个位置

// save time prior to invocation

// 调用静态的long java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入operand stack操作数堆栈

ilist.append(ifact.createInvoke("java.lang.System",

"currentTimeMillis", Type.LONG, Type.NO_ARGS,

Constants.INVOKESTATIC));

ilist.append(InstructionFactory.createStore(Type.LONG, slot));// 将operand stack的top保存到本地变量堆栈的slot位置,operand stack弹出long值

// call the wrapped method

int offset = 0; // 偏移量

short invoke = Constants.INVOKESTATIC; // 预先设置为调用静态函数

if (!methgen.isStatic()) { // 如果不是调用静态函数,将调用的第一个(隐藏的)参数(目标对象的this引用)压入operand stack

ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));

offset = 1;// 偏移量加1

invoke = Constants.INVOKEVIRTUAL;// 设置为调用非静态函数

}

for (int i = 0; i < types.length; i++) { // 遍历所有参数

Type type = types[i];

ilist.append(InstructionFactory.createLoad(type, offset)); // 按参数类型把参数一个个从本地变量堆栈取出,压入operand stack

offset += type.getSize();

}

Type result = methgen.getReturnType();// 取得要调用函数的返回值类型

ilist.append(ifact.createInvoke(cname, iname, result, types, invoke));// 调用方法名为iname的函数

// store result for return later

if (result != Type.VOID) {

ilist.append(InstructionFactory.createStore(result, slot + 2)); // 将名为iname的函数返回值复制到本地变量堆栈的slot+2的位置上

}

// print time required for method call

// 获取静态对象java.lang.System.out的引用,返回值压入operand stack

ilist.append(ifact.createFieldAccess("java.lang.System", "out",

new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));

ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。完成后load_stack的头两个元素是静态对象java.lang.System.out的引用

ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。现在有3个java.lang.System.out的引用。供下面3次调用out.print()函数使用

String text = "Call to method " + methgen.getName() + " took ";

ilist.append(new PUSH(pgen, text));// 将text放入pgen(代表常量池),并把其在pgen的引用压入operand stack(供out.print(Sting)调用的参数)

ilist.append(ifact.createInvoke("java.io.PrintStream", "print",

Type.VOID, new Type[] { Type.STRING },

Constants.INVOKEVIRTUAL));// 调用结束,operand stack弹出一个String的引用和一个out的引用(还剩2个out),函数没有返回值

ilist.append(ifact.createInvoke("java.lang.System",

"currentTimeMillis", Type.LONG, Type.NO_ARGS,

Constants.INVOKESTATIC));// 调用java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入堆栈operand stack

ilist.append(InstructionFactory.createLoad(Type.LONG, slot));// 从本地变量堆栈的slot位置载入先前储存的long值,压入operand stack

ilist.append(InstructionConstants.LSUB);// 调用long的减法指令,弹出2个long值,并把结果压入operand stack,现在operand stack的top第一个是long,第二个是out的引用

ilist.append(ifact.createInvoke("java.io.PrintStream", "print",

Type.VOID, new Type[] { Type.LONG }, Constants.INVOKEVIRTUAL));// 调用out.print(long)方法

ilist.append(new PUSH(pgen, " ms."));// 将String对象" ms."放入pgen,并把其在pgen的引用压入operand stack(供out.print(Sting)调用的参数)

ilist

.append(ifact.createInvoke("java.io.PrintStream", "println",

Type.VOID, new Type[] { Type.STRING },

Constants.INVOKEVIRTUAL));

// return result from wrapped method call

if (result != Type.VOID) {

ilist.append(InstructionFactory.createLoad(result, slot + 2));// 处理返回值,如果不为空,从本地对象堆栈的slot+2位置读取指定类型的返回值压入operand stack

}

ilist.append(InstructionFactory.createReturn(result)); //调用处理返回值的指令,result为返回值的类型

//下面是一下扫尾工作

// finalize the constructed method

wrapgen.stripAttributes(true);

wrapgen.setMaxStack();

wrapgen.setMaxLocals();

cgen.addMethod(wrapgen.getMethod());

ilist.dispose();

}

public static void main(String[] argv) {

if (argv.length == 2 && argv[0].endsWith(".class")) {

try {

JavaClass jclas = new ClassParser(argv[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(argv[1])) {

break;

}

}

if (index < methods.length) {

addWrapper(cgen, methods[index]);

FileOutputStream fos = new FileOutputStream(argv[0]);

cgen.getJavaClass().dump(fos);

fos.close();

} else {

System.err.println("Method " + argv[1] + " not found in "

+ argv[0]);

}

} catch (IOException ex) {

ex.printStackTrace(System.err);

}

} else {

System.out.println("Usage: BCELTiming class-file method-name");

}

}

}

代码比较难懂,有待日后深入讨论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐