ASM。正确克隆 JumpInsnNode

ASM. Clone JumpInsnNode correctly

你知道如何正确克隆JumpInsnNode吗?

我尝试了几种方法:

1. endList.add(insn.clone(labelNodes));

insn在这里就是JumpInsnNode; labelNodes - 方法中的所有 labelNodes。 由于从 AbsractInsnNode 类调用克隆方法的克隆方法的实现,此代码抛出 NullPointerException:

static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> map) {
        return map.get(label);
    }

此方法return无效。

  1. endList.add(new JumpInsnNode(insn.getOpcode(), new LabelNode(insn.label.getLabel())));

抛出异常:

java.lang.ArrayIndexOutOfBoundsException: 0
    at org.objectweb.asm.Frame.a(Unknown Source)
    at org.objectweb.asm.Frame.a(Unknown Source)
    at org.objectweb.asm.MethodWriter.visitMaxs(Unknown Source)
    at org.objectweb.asm.tree.MethodNode.accept(Unknown Source)
    at org.objectweb.asm.tree.MethodNode.accept(Unknown Source)
    at org.objectweb.asm.tree.ClassNode.accept(Unknown Source)
    at com.smartbear.real.agent.Agent.transform(Agent.java:221)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
    at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
    at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
    at com.smartbear.real.agent.Agent.agentmain(Agent.java:118)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:382)
    at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:407)

推理:我需要能够再次加载方法 return 值。我能够通过其他类型的指令做到这一点。然而,这种类型的指令:return (test != null); 现在对我不起作用。字节码:

  LINENUMBER 112 L2
    ALOAD 3: tr
    IFNULL L3
    ICONST_1
    IRETURN
   L3
   FRAME APPEND [Boolean]
    ICONST_0
    IRETURN

看来你用错了方法。您不应该克隆任意指令来复制 return 值,这不仅会变得不必要的复杂,还可能会复制副作用,从而产生不同于没有 Instrumentation 的意外行为。

复制值,一个方法即将return,就简单多了。在执行 …RETURN 指令之一之前,操作数堆栈中必须有实际的 return 值。因此,您所要做的就是在 …RETURN 指令之前插入适当的 DUP 指令(DUPDUP2)以复制该值。然后您可以插入使用该重复值的日志记录代码。

例如您可以将 IRETURN 的出现次数更改为:

DUP
INVOKESTATIC java/lang/Integer valueOf (I)Ljava/lang/Integer;
INVOKESTATIC MyLogger logReturnValue (Ljava/lang/Object;)V
IRETURN // the original return instruction

DRETURN至:

DUP2
INVOKESTATIC java/lang/Double valueOf (D)Ljava/lang/Double;
INVOKESTATIC MyLogger logReturnValue (Ljava/lang/Object;)V
DRETURN // the original return instruction

ARETURN至:

DUP
INVOKESTATIC MyLogger logReturnValue (Ljava/lang/Object;)V
ARETURN // the original return instruction

等等