gpt4 book ai didi

java - ASM Java 替换方法调用指令

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:45:33 31 4
gpt4 key购买 nike

背景

我想使用 ASM Java 框架对一些耗时的方法例如 org/json/JSONObject.toString() 做一些检测工作。

方法的原始调用

public class JSONUsage {
public void callToString() {
JSONObject jsonObject = new JSONObject();
String a = jsonObject.toString();//original call
System.out.println(a);
}
}

检测后

public class JSONUsage {
public void callToString() {
JSONObject jsonObject = new JSONObject();
// **important!**
//pass the instance as an param, replace the call to a static method
String a = JSONReplacement.jsonToString(jsonObject);
System.out.println(a);
}
}

public class JSONReplacement {

public static String jsonToString(JSONObject jsonObject) {
//do the time caculation
long before = System.currentTimeMillis();
String ret = jsonObject.toString();
long elapsed = System.currentTimeMillis() - before;

return ret;
}
}

使用ASM框架3.0

ClassReader cr = new ClassReader("JSONUsage");
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
ReplaceClassVisitor replaceClassVisitor = new ReplaceClassVisitor(cw);

cr.accept(replaceClassVisitor, ClassReader.EXPAND_FRAMES);

问题:如何使用 ASM API 获得通用解决方案?

public class ReplaceClassVisitor extends ClassAdapter {

public ReplaceClassVisitor(ClassVisitor cv) {
super(cv);
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new MethodReplaceMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc);
}

private static final class MethodReplaceMethodVisitor extends GeneratorAdapter {

public MethodReplaceMethodVisitor(MethodVisitor mv, int access, String name, String desc) {
super(mv, access, name, desc);
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
//org/json/JSONObject.toString() here is a example,
//i want a general instruction
if (owner.equals("org/json/JSONObject") && name.equals("toString")) {
replaceCall(opcode, owner, name, desc);
}
}

private void replaceCall(int opcode, String owner, String name, String desc) {
//how can i have a general asm instruction to manipulate this method call?
}

}
}

最佳答案

您不需要“操纵”方法调用。关键是您的访问者通过将每个传入的访问者调用中继给编写者来生成代码,并且您正在方便地继承执行此 1:1 的实现。

因此,您未覆盖的每个 visit... 方法都会将每次调用委托(delegate)给编写器,从而产生完全相同的指令。这同样适用于重写的方法,当它们委托(delegate)给它们的原始 super 实现传递相同的参数时。当您覆盖一个方法并且不中继调用时,相应的指令不会被复制、读取、有效地删除。当您调用其他 visit... 方法(而不是)时,您将生成其他指令。

private static final class MethodReplaceMethodVisitor extends GeneratorAdapter {

public MethodReplaceMethodVisitor(
MethodVisitor mv, int access, String name, String desc) {
super(mv, access, name, desc);
}

@Override
public void visitMethodInsn(
int opcode, String owner, String name, String desc, boolean itf) {

if(opcode==Opcodes.INVOKEVIRTUAL && owner.equals("org/json/JSONObject")
&& name.equals("toString") && desc.equals("()Ljava/lang/String;")) {
// not relaying the original instruction to super effectively removes the original
// instruction, instead we're producing a different instruction:
super.visitMethodInsn(Opcodes.INVOKESTATIC, "whatever/package/JSONReplacement",
"jsonToString", "(Lorg/json/JSONObject;)Ljava/lang/String;", false);
}
else // relaying to super will reproduce the same instruction
super.visitMethodInsn(opcode, owner, name, desc, itf);
}

// all other, not overridden visit methods reproduce the original instructions
}

所以上面的代码截取了您感兴趣的指令并且不会重现它,而是生成所需的 invokestatic 指令。这不需要额外的调整就可以工作,因为你的静态方法调用将从堆栈中消耗一个 JSONObject 并产生一个 String,就像原始调用一样,所以对周围没有影响代码。

关于java - ASM Java 替换方法调用指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35617471/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com