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无效。
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
指令(DUP
或 DUP2
)以复制该值。然后您可以插入使用该重复值的日志记录代码。
例如您可以将 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
等等
你知道如何正确克隆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无效。
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
指令(DUP
或 DUP2
)以复制该值。然后您可以插入使用该重复值的日志记录代码。
例如您可以将 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
等等