- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
对于我的论文研究,我需要将一段代码注入(inject)到我没有源代码的测试套件(在本例中为 DaCapo 基准测试套件,http://dacapobench.org/)中的可定义方法中。我论文的这一部分所基于的先前研究为此使用了字节码注入(inject),这导致我也这样做了。
我使用 Apache 的 BCEL 库 ( http://commons.apache.org/proper/commons-bcel/ ) 构建了一个小程序,使我能够在其他语句之前将斐波那契算法注入(inject)方法主体。
现在,我做了这个,但它不能正常工作。我注入(inject)的一些方法运行良好(因为它们由于斐波那契代码而变慢),并且运行 DaCapo 框架运行良好,而其他注入(inject)的方法会破坏代码。
问题是,我不知道为什么,即使我知道哪些方法失败了,哪些方法成功了,但我无法在失败的方法中找到重复出现的模式。
我可以粘贴一些失败的方法,但这会使这篇文章比现在更长。所以我想知道,是否有什么我没有考虑或忽略的事情?
下面是一个示例 java 文件、它的结果和我编写的 BCEL 程序。
一个简单的例子,我有一个名为 DemoClass.java 的 java 文件:
public class DemoClass {
public static void main(String[] argv) {
System.out.println("Demo body");
test();
}
public static void test() {
System.out.println("Demo test");
}
}
在我的 shell 中调用以下 java 命令后:
javac DemoClass.java; java -cp bcel-5.2.jar:. InjectCodeBCEL DemoClass 测试 123456789 ; Java 演示类
(bcel-5.2.jar文件可以在前面提到的apache网站上找到)
程序看起来像这样:
public class DemoClass {
public static void main(String[] argv) {
System.out.println("Demo body");
test();
}
public static void test() {
int[] fibNumbers = new int[100];
for (int i = 0; i < 123456789; i++) {
int j = i % 100;
if (i == 0) {
fibNumbers[i] = 0;
}
else if (i == 1) {
fibNumbers[i] = 1;
}
else {
int k = (i - 1) % 100;
int m = (i - 2) % 100;
int n = fibNumbers[k] + fibNumbers[m];
fibNumbers[j] = n;
}
}
System.out.println("Demo test");
}
}
这是 InjectCodeBCEL.java 的代码:
import java.io.IOException;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import org.apache.bcel.*;
public class InjectCodeBCEL {
static public void main(String args[]) {
//Get class to modify from program argument
JavaClass mod = null;
String methodName = (args.length >= 2) ? args[1] : "";
int loopsize = (args.length >= 3) ? Integer.parseInt(args[2]) : 1;
try {
mod = Repository.lookupClass(args[0]);
}
catch (Exception e) {
System.err.println("Could not get class " + args[0]);
return;
}
//Create a generic class to modify
ClassGen modClass = new ClassGen(mod);
//Create a generic constantpool to modify
ConstantPoolGen cp = modClass.getConstantPool();
boolean methodEdited = false;
Method[] methods = mod.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName)) {
System.out.println("Method: " + methods[i]);
// System.out.println("before:\n" + methods[i].getCode());
modClass.removeMethod(methods[i]);
Method newMethod = insertCodeInMethod(mod, methods[i], cp, loopsize);
// System.out.println("after:\n" + newMethod.getCode());
modClass.addMethod(newMethod);
methodEdited = true;
}
}
if (methodEdited) {
modClass.update();
try {
//Write modified class
JavaClass newClass = modClass.getJavaClass();
String classname = args[0].replace(".","/");
newClass.dump(classname + ".class");
System.out.println("Class " + classname + " modified");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
public static Method insertCodeInMethod(JavaClass mod, Method method, ConstantPoolGen cp, int loopsize) {
MethodGen mg = new MethodGen(method, mod.getClassName(), cp);
InstructionList il = mg.getInstructionList();
InstructionHandle ihs = il.getStart();
InstructionList ils = new InstructionList();
InstructionFactory f = new InstructionFactory(cp);
String CLASS_NAME = mod.getClassName();
int ARRAY_SIZE = 100;
int LOOP_SIZE = loopsize;
int INCREASE_ID = mg.isStatic() ? 0 : 1; // if not static, this has position 0 on the stack
Type[] types = mg.getArgumentTypes();
// Increase the stack location(?) so they don't collide with the methods parameters.
for (int i = 0; i < types.length; i++) {
INCREASE_ID += types[i].getSize();
}
int VAR_ARRAY = 0 + INCREASE_ID;
int VAR_I = 1 + INCREASE_ID;
int VAR_II = 2 + INCREASE_ID;
int VAR_I_MIN_1 = 3 + INCREASE_ID;
int VAR_I_MIN_2 = 4 + INCREASE_ID;
int VAR_SUM = 5 + INCREASE_ID;
int VAR_JUMPTO = 6 + INCREASE_ID;
// init array
ils.append(new PUSH(cp, ARRAY_SIZE));
ils.append(new NEWARRAY(Type.INT));
ils.append(new ASTORE(VAR_ARRAY));
// create iterator = 0 for while
ils.append(new PUSH(cp, 0));
ils.append(new ISTORE(VAR_I));
// Main while loop:
InstructionHandle beforeWhile = ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, LOOP_SIZE));
// While condition:
BranchHandle whileCondition = ils.append(new IF_ICMPLT(null)); // if (VAR_I < LOOP_SIZE): jump to "whileBody"
BranchHandle whileConditionFalseGoto = ils.append(new GOTO(null)); // if not: jump to "afterWhile"
// While body:
InstructionHandle whileBody = ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, ARRAY_SIZE));
ils.append(new IREM());
ils.append(new ISTORE(VAR_II)); // create int ii = i % ARRAY_SIZE;
// if (i == 0)
ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 0));
BranchHandle ifIteratorIs0 = ils.append(new IF_ICMPEQ(null));
BranchHandle ifIteratorIs0FalseGoto = ils.append(new GOTO(null));
// If true body
InstructionHandle ifIteratorIs0Body = ils.append(new ALOAD(VAR_ARRAY));
ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 0));
ils.append(new IASTORE());
BranchHandle ifIteratorIs0Done = ils.append(new GOTO(null));
// "else" if (i != 1)
InstructionHandle beginIfIteratorIsNot1 = ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 1));
BranchHandle ifIteratorIsNot1 = ils.append(new IF_ICMPNE(null));
// false: else: so in this case: if (!(i != 1)):
ils.append(new ALOAD(VAR_ARRAY));
ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 1));
ils.append(new IASTORE());
// done, go to i++;
BranchHandle ifIteratorIsNot1FalseGoto = ils.append(new GOTO(null));
// If true body (so if i != 1)..
// create variable VAR_I_MIN_1 for array index (i-1)
InstructionHandle ifIteratorIsNot1Body = ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 1));
ils.append(new ISUB());
ils.append(new PUSH(cp, ARRAY_SIZE));
ils.append(new IREM());
ils.append(new ISTORE(VAR_I_MIN_1)); // create int i_min_1 = (i - 1) % ARRAY_SIZE;
// create variable VAR_I_MIN_2 for array index (i-2)
ils.append(new ILOAD(VAR_I));
ils.append(new PUSH(cp, 2));
ils.append(new ISUB());
ils.append(new PUSH(cp, ARRAY_SIZE));
ils.append(new IREM());
ils.append(new ISTORE(VAR_I_MIN_2)); // create int i_min_2 = (i - 2) % ARRAY_SIZE;
// load the array values:
ils.append(new ALOAD(VAR_ARRAY));
ils.append(new ILOAD(VAR_I_MIN_1));
ils.append(new IALOAD());
ils.append(new ALOAD(VAR_ARRAY));
ils.append(new ILOAD(VAR_I_MIN_2));
ils.append(new IALOAD());
// add the two values, and save them
ils.append(new IADD());
ils.append(new ISTORE(VAR_SUM));
// add the new calculated number to the array
ils.append(new ALOAD(VAR_ARRAY));
ils.append(new ILOAD(VAR_II));
ils.append(new ILOAD(VAR_SUM));
ils.append(new IASTORE());
// Done; go to i++;
BranchHandle ifIteratorIsNot1Done = ils.append(new GOTO(null));
// Increment i with 1
InstructionHandle generalIfDoneGoto = ils.append(new IINC(VAR_I,1));
// Goto that whil restart this loop:
BranchHandle whileGotoBegin = ils.append(new GOTO(null)); // jumps to "beforeWhile"
// We need something to jump to when done with the outer loop.
InstructionHandle afterWhile = ils.append(new PUSH(cp, 0));
ils.append(new ISTORE(VAR_JUMPTO));
// While targets:
whileCondition.setTarget(whileBody);
whileConditionFalseGoto.setTarget(afterWhile);
whileGotoBegin.setTarget(beforeWhile);
// if (i == 0)
ifIteratorIs0.setTarget(ifIteratorIs0Body);
ifIteratorIs0FalseGoto.setTarget(beginIfIteratorIsNot1);
ifIteratorIs0Done.setTarget(generalIfDoneGoto);
// if (i == 1)
ifIteratorIsNot1.setTarget(ifIteratorIsNot1Body);
ifIteratorIsNot1FalseGoto.setTarget(generalIfDoneGoto);
ifIteratorIsNot1Done.setTarget(generalIfDoneGoto);
InstructionHandle ihss = il.insert(ihs,ils);
il.redirectBranches(ihs, ihss);
il.update();
mg.setMaxStack();
mg.setMaxLocals();
mg.update();
return mg.getMethod();
}
}
更新
下面是在 net.sourceforge.pmd.AbstractRuleChainVisitor 中注入(inject) visitAll 方法失败后的完整错误
===== DaCapo 9.12 pmd starting =====
java.lang.reflect.InvocationTargetException
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.dacapo.harness.Pmd.iterate(Pmd.java:58)
at org.dacapo.harness.Benchmark.run(Benchmark.java:166)
at org.dacapo.harness.TestHarness.runBenchmark(TestHarness.java:218)
at org.dacapo.harness.TestHarness.main(TestHarness.java:171)
at Harness.main(Harness.java:17)
Caused by: java.lang.ClassFormatError: LVTT entry for 'nodes' in class file net/sourceforge/pmd/AbstractRuleChainVisitor does not match any LVT entry
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.dacapo.harness.DacapoClassLoader.loadClass(DacapoClassLoader.java:124)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.dacapo.harness.DacapoClassLoader.loadClass(DacapoClassLoader.java:124)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at net.sourceforge.pmd.RuleSets.<init>(RuleSets.java:27)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:82)
at net.sourceforge.pmd.RuleSetFactory.createRuleSets(RuleSetFactory.java:70)
at net.sourceforge.pmd.PMD.doPMD(PMD.java:359)
at net.sourceforge.pmd.PMD.main(PMD.java:415)
... 9 more
该方法的代码(由JD-GUI生成):
public void visitAll(List<CompilationUnit> astCompilationUnits, RuleContext ctx)
{
initialize();
clear();
long start = System.nanoTime();
indexNodes(astCompilationUnits, ctx);
long end = System.nanoTime();
Benchmark.mark(8, end - start, 1L);
for (RuleSet ruleSet : this.ruleSetRules.keySet())
if (ruleSet.applies(ctx.getSourceCodeFile()))
{
visits = 0;
start = System.nanoTime();
for (Rule rule : (List)this.ruleSetRules.get(ruleSet)) {
List nodeNames = rule.getRuleChainVisits();
for (int j = 0; j < nodeNames.size(); j++) {
List nodes = (List)this.nodeNameToNodes.get(nodeNames.get(j));
for (SimpleNode node : nodes)
{
while ((rule instanceof RuleReference)) {
rule = ((RuleReference)rule).getRule();
}
visit(rule, node, ctx);
}
visits += nodes.size();
}
end = System.nanoTime();
Benchmark.mark(1, rule.getName(), end - start, visits);
start = end;
}
}
int visits;
}
这是一个与我的代码错过“insertCodeInMethod”中堆栈位置增加部分时得到的错误相当的错误。这导致参数和非静态的 this 与斐波那契代码中定义的变量发生冲突。
最佳答案
LVTT
代表LocalVariableTypeTable
,LVT
代表LocalVariableTable
。这些是在更改方法时必须调整或删除的调试信息。
顺便说一句,将大量代码注入(inject)一个方法并不是一个成功的好方法,因为它会产生各种错误来源,意味着重新发明轮子(构建编译器)并导致转换后的代码重复类。大多数使用代码注入(inject)/类文件转换的应用程序只会注入(inject)对预编译方法的少量调用。
关于java - 使用 BCEL 在现有方法中注入(inject)代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19119702/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!