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");
}
}
}
代码比较难懂,有待日后深入讨论。
简介: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");
}
}
}
代码比较难懂,有待日后深入讨论。
相关文章推荐
- IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool问题解决方案
- Android Studio Project debug library show source code does not match the bytecode
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 60
- IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 18
- maven org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 60
- Java bytecode library
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 18
- org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 60
- Android studio gradle编译问题:Cause: Dex cannot parse version 52 byte code. This is caused by library de
- Javassist: Java Bytecode Engineering Made Simple
- Trace every instruction in java bytecode using BCEL
- Apache Mahout 简介
- Apache---DBUtils框架简介
- Java SSH库使用简介:Apache sshd和JSch(Java Secure Channel)
- Unity iOS can handle SQLite even with Byte-Code Stripping on.
- Failed to load or instantiate TagLibraryValidator class: org.apache.taglibs.standard.tlv.JstlFmtTLV
- Living in the Matrix with Bytecode Manipulation--转
- xcode Code Snippets Library 快速代码块