下面列出了org.objectweb.asm.Opcodes# DUP2 ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Mutates a primitive double return (<code>Opcode.DRETURN</code>). The
* strategy used was translated from jumble BCEL code. The following is
* complicated by the problem of <tt>NaN</tt>s. By default the new value is
* <code>-(x + 1)</code>, but this doesn't work for <tt>NaN</tt>s. But for a
* <tt>NaN</tt> <code>x != x</code> is true, and we use this to detect them.
*
* @see #mutatePrimitiveFloatReturn()
*/
private void mutatePrimitiveDoubleReturn() {
if (shouldMutate("primitive double", "(x != NaN)? -(x + 1) : -1 ")) {
final Label label = new Label();
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.DCMPG);
super.visitJumpInsn(Opcodes.IFEQ, label);
super.visitInsn(Opcodes.POP2);
super.visitInsn(Opcodes.DCONST_0);
// the following code is executed in NaN case, too
super.visitLabel(label);
super.visitInsn(Opcodes.DCONST_1);
super.visitInsn(Opcodes.DADD);
super.visitInsn(Opcodes.DNEG);
super.visitInsn(Opcodes.DRETURN);
}
}
public static int getDupOpcode(Type type) {
if (type.getSize() == 1) {
return Opcodes.DUP;
} else if (type.getSize() == 2) {
return Opcodes.DUP2;
} else {
throw new IllegalArgumentException(type.toString());
}
}
private void instrumentToTrackReturn(int opcode) {
if (!VariableType.isReturnOperation(opcode)) {
return;
}
if (Opcodes.RETURN == opcode) {
super.visitLdcInsn(lineNumber);
super.visitLdcInsn(methodName);
super.visitLdcInsn(Type.getType("L" + className + ";"));
super.visitMethodInsn(Opcodes.INVOKESTATIC, instrumentationActions.trackerClass, "trackReturn", "(ILjava/lang/String;Ljava/lang/Class;)V", false);
} else {
if (opcode == Opcodes.DRETURN || opcode == Opcodes.LRETURN) {
super.visitInsn(Opcodes.DUP2);
} else {
super.visitInsn(Opcodes.DUP);
}
final VariableType variableType;
if (opcode == Opcodes.IRETURN) {
variableType = VariableType.getReturnTypeFromMethodDesc(desc);
} else {
variableType = VariableType.getByReturnOpCode(opcode);
}
super.visitLdcInsn(lineNumber);
super.visitLdcInsn(methodName);
super.visitLdcInsn(Type.getType("L" + className + ";"));
super.visitMethodInsn(Opcodes.INVOKESTATIC, instrumentationActions.trackerClass, "trackReturn", "(" + variableType.desc + "ILjava/lang/String;Ljava/lang/Class;)V", false);
}
}
/**
* If this is a ReturnEventInfo AND we are right before a RETURN opcode (so
* we can expect the *original* return value to be on the stack, then we dup
* the return value into a local var so we can push it later when we invoke
* the ReturnEventInfo ctor
*
* @param callback callback handle
*/
private void dupReturnValue(final Callback callback) {
if (!callback.isAtReturn) {
return;
}
int dupCode = callback.target.returnType.getSize() == 1 ? Opcodes.DUP : Opcodes.DUP2;
callback.add(new InsnNode(dupCode));
callback.add(new VarInsnNode(callback.target.returnType.getOpcode(Opcodes.ISTORE), callback.marshalVar()));
}
/**
* NOTE: All calls to instruction visitation routines are made against super, directly, since we do frame offset accounting within our overrides
* and that offset only applies to incoming bytecodes, not outgoing ones.
*
* @param opcode The opcode.
* @param descriptor The type descriptor of the field to which the opcode is applied.
*/
private void checkInjectLazyLoad(int opcode, String descriptor) {
// If this is a PUTFIELD or GETFIELD, we want to call "lazyLoad()":
// -PUTIFELD: DUP2, POP, INVOKEVIRTUAL
// -GETIFELD: DUP, INVOKEVIRTUAL
if ((Opcodes.PUTFIELD == opcode) && ((null == this.tracker) || !this.tracker.isThisTargetOfPut(this.frameOffset))) {
// We need to see how big this type is since double and long need a far more complex dance.
if ((1 == descriptor.length()) && ((DescriptorParser.LONG == descriptor.charAt(0)) || (DescriptorParser.DOUBLE == descriptor.charAt(0)))) {
// Here, the stack looks like: ... OBJECT, VAR1, VAR2 (top)
// Where we need: ... OBJECT, VAR1, VAR2, OBJECT (top)
// This is multiple stages:
// DUP2_X1: ... VAR1, VAR2, OBJECT, VAR1, VAR2 (top)
super.visitInsn(Opcodes.DUP2_X1);
// POP2: ... VAR1, VAR2, OBJECT (top)
super.visitInsn(Opcodes.POP2);
// DUP: ... VAR1, VAR2, OBJECT, OBJECT (top)
super.visitInsn(Opcodes.DUP);
// INOKE: ... VAR1, VAR2, OBJECT (top)
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
// DUP_X2: ... OBJECT, VAR1, VAR2, OBJECT (top)
super.visitInsn(Opcodes.DUP_X2);
// POP: ... OBJECT, VAR1, VAR2 (top)
super.visitInsn(Opcodes.POP);
} else {
// Here, the stack looks like: ... OBJECT, VAR, (top)
// Where we need: ... OBJECT, VAR, OBJECT (top)
// Stages:
// DUP2: ... OBJECT, VAR, OBJECT, VAR (top)
super.visitInsn(Opcodes.DUP2);
// POP: ... OBJECT, VAR, OBJECT (top)
super.visitInsn(Opcodes.POP);
// INOKE: ... OBJECT, VAR (top)
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
}
} else if ((Opcodes.GETFIELD == opcode) && ((null == this.tracker) || !this.tracker.isThisTargetOfGet(this.frameOffset))) {
// Here, the stack looks like: ... OBJECT, (top)
// Where we need: ... OBJECT, OBJECT (top)
super.visitInsn(Opcodes.DUP);
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
}
}
public void visitFieldInsn(int opcode, String owner, String fieldName,
String desc) {
if (firstInstruction)
addInc();
if (logPointerChange && opcode == Opcodes.PUTFIELD
&& desc.charAt(0) == 'L') {
if (constructor && !doneSuperConstructor && name.equals(owner)
&& finalFields.contains(fieldName))
delayedFieldPointer.put(fieldName, desc);
else {
// instrument reference changes from
// putfield ...,obj,v' => ...
// to
// dup2 ...,obj,v' => ...,obj,v',obj,v'
// swap ...,obj,v',obj,v' => ...,obj,v',v',obj
// dup ...,obj,v',v',obj => ...,obj,v',v',obj,obj
// getfield ...,obj,v',v',obj,obj => ...,obj,v',v',obj,v
// invokespecial
// pointerchangelog(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
// ...,obj,v',v',obj,v => ...,obj,v'
// putfield ...,obj,v' =>
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.SWAP);
super.visitInsn(Opcodes.DUP);
super.visitFieldInsn(Opcodes.GETFIELD, owner, fieldName,
desc);
super.visitMethodInsn(Opcodes.INVOKESTATIC, name,
LOG_INTERNAL_POINTER_CHANGE,
POINTER_CHANGE_SIGNATURE);
}
} else if (logPointerChange && opcode == Opcodes.PUTSTATIC
&& desc.charAt(0) == 'L') {
// if (finalFields.contains(fieldName)) {
// // assume field is initially null
// super.visitInsn(Opcodes.DUP);
// } else {
// instrument reference changes from
// putstatic ...,v' => ...
// to
// dup ...,v' => ...,v',v'
// ldc owner.class ...,v',v' => ...,v',v',k
// getstatic ...,v',v',k => ...,v',v',k,v
// invokespecial
// staticpointerchangelog(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Object;)V
// ...,v',v',k,v => ...,v'
super.visitInsn(Opcodes.DUP);
super.visitLdcInsn(Type.getObjectType(owner));
super.visitFieldInsn(Opcodes.GETSTATIC, owner, fieldName, desc);
super.visitMethodInsn(Opcodes.INVOKESTATIC, name,
LOG_INTERNAL_STATIC_POINTER_CHANGE,
STATIC_POINTER_CHANGE_SIGNATURE);
// }
}
super.visitFieldInsn(opcode, owner, fieldName, desc);
}