我想编写一个MethodVisitor来转换用于乘法的LDC指令。
字节码示例:
ldc #26
imul
这基本上推动了一个常数然后乘以它。
它必须是有状态的转换,因为我首先必须检查它是否为乘法,如果是,我需要返回到ldc指令并修改常量。我不完全确定我会怎么做,我不知道如何修改常量(当我尝试传递一个不同的值时,旧值仍然保留在常量池中。)
编辑:
public class AdditionTransformer extends MethodAdapter {
boolean replace = false;
int operand = 0;
AdditionTransformer(MethodVisitor mv) {
super(mv);
}
@Override
public void visitInsn(int opcode) {
if (opcode == IMUL && replace) {
operand *= 2;
visitLdcInsn(operand);
replace = false;
}
mv.visitInsn(opcode);
}
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof Integer && !replace) {
operand = (Integer) cst;
replace = true;
} else {
mv.visitLdcInsn(cst);
}
}
}
这就是我所拥有的,但它不会删除常量池中的旧值,并且可能存在错误。
答案 0 :(得分:1)
你所拥有的只是正确的,但是不能满足在ldc之后调用的其他类型的操作码,所以你会在那里造成一些破坏,因为他们会在堆栈上寻找一些东西不存在(因为你没有访问ldc)。我不太确定删除现有常量,但你可以像这样替换常量:
@Override
public void visitInsn(int opcode) {
if (opcode == IMUL && replace) {
operand *= 2;
mv.visitInsn(POP);
mv.visitLdcInsn(operand);
replace = false;
}
mv.visitInsn(opcode);
}
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof Integer && !replace) {
operand = (Integer) cst;
replace = true;
}
mv.visitLdcInsn(cst);
}
换句话说,请始终访问“ldc”。如果你看到一个IMUL继续它,弹出堆栈,插入一个新的常量,然后访问IMUL操作码。如果在访问ldc之后和IMUL之前访问了一些其他方法,则需要做一些工作才能使其完全安全。要偏执,你可以覆盖所有访问者方法,如果它不是visitInsn或不是IMUL,你将访问ldc并设置replace = false。
完全取代常数有点棘手。你需要记住到目前为止在类中访问过的所有方法都看到了哪些常量。如果到目前为止还没有看到该常量,则可以在访问ldc时替换该值。
答案 1 :(得分:1)
如果您有兴趣以这种方式修改字节码,您可能需要查看ASM tree API。您可以通过更舒适的DOM样式树界面轻松替换LdcInsnNode.cst,而不是您尝试使用的SAX样式的访问者界面。