下面列出了org.objectweb.asm.Opcodes# SWAP 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private List<AbstractInsnNode> getPossibleSwap(AbstractInsnNode ain, int mode)
{
AbstractInsnNode next = ain;
List<AbstractInsnNode> instrs = new ArrayList<>();
while(next != null)
{
if(Utils.isInstruction(next) && next.getOpcode() != Opcodes.IINC)
instrs.add(next);
if(instrs.size() >= (mode == 0 ? 3 : 4))
break;
next = next.getNext();
}
if(mode == 0 && instrs.size() >= 3 && willPush(instrs.get(0)) && willPush(instrs.get(1))
&& instrs.get(2).getOpcode() == Opcodes.SWAP)
return instrs;
else if(mode == 1 && instrs.size() >= 4 && willPush(instrs.get(0))
&& (willPush(instrs.get(1)) || instrs.get(1).getOpcode() == Opcodes.DUP)
&& instrs.get(2).getOpcode() == Opcodes.GETFIELD
&& Type.getType(((FieldInsnNode)instrs.get(2)).desc).getSort() != Type.LONG
&& Type.getType(((FieldInsnNode)instrs.get(2)).desc).getSort() != Type.DOUBLE
&& instrs.get(3).getOpcode() == Opcodes.SWAP)
return instrs;
else
return null;
}
private void buildRecorderFromObject(
int opcode, String owner, String name, String signature, boolean itf) {
super.visitMethodInsn(opcode, owner, name, signature, itf);
// -> stack: ... newobj
super.visitInsn(Opcodes.DUP);
// -> stack: ... newobj newobj
super.visitInsn(Opcodes.DUP);
// -> stack: ... newobj newobj newobj
// We could be instantiating this class or a subclass, so we
// have to get the class the hard way.
super.visitMethodInsn(
Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
// -> stack: ... newobj newobj Class
super.visitInsn(Opcodes.SWAP);
// -> stack: ... newobj Class newobj
super.visitMethodInsn(
Opcodes.INVOKESTATIC, recorderClass, recorderMethod, CLASS_RECORDER_SIG, false);
// -> stack: ... newobj
}
private void invokeRecordAllocation(String typeName) {
Matcher matcher = namePattern.matcher(typeName);
if (matcher.find()) {
typeName = matcher.group(1);
}
// stack: ... count newobj
super.visitInsn(Opcodes.DUP_X1);
// -> stack: ... newobj count newobj
super.visitLdcInsn(typeName);
// -> stack: ... newobj count newobj typename
super.visitInsn(Opcodes.SWAP);
// -> stack: ... newobj count typename newobj
super.visitMethodInsn(
Opcodes.INVOKESTATIC, recorderClass, recorderMethod, RECORDER_SIGNATURE, false);
// -> stack: ... newobj
}
private void genericSswap(String desc) {
//caters for double, int on stack - to swap
if(desc.equals("J") || desc.equals("D")){//long and double take up two slots insteead of 1
super.visitInsn(Opcodes.DUP_X2);
super.visitInsn(Opcodes.POP);
}
else{//1 slot each
super.visitInsn(Opcodes.SWAP);
}
}
public SwapFrame(Frame top, Frame bottom) {
super (Opcodes.SWAP);
this.top = top;
this.bottom = bottom;
this.top.children.add(this);
this.bottom.children.add(this);
}
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);
}
void calculateArrayLengthAndDispatch(String typeName, int dimCount) {
// Since the dimensions of the array are not known at instrumentation
// time, we take the created multi-dimensional array and peel off nesting
// levels from the left. For each nesting layer we probe the array length
// and accumulate a partial product which we can then feed the recording
// function.
// below we note the partial product of dimensions 1 to X-1 as productToX
// (so productTo1 == 1 == no dimensions yet). We denote by aref0 the
// array reference at the current nesting level (the containing aref's [0]
// element). If we hit a level whose arraylength is 0 or whose
// reference is null, there's no point continuing, so we shortcut
// out.
// This approach works pretty well when you create a new array with the
// newarray bytecodes. You can also create a new array by cloning an
// existing array; an existing multidimensional array might have had some
// of its [0] elements nulled out. We currently deal with this by bailing
// out, but arguably we should do something more principled (like calculate
// the size of the multidimensional array from scratch if you are using
// clone()).
// TODO(java-platform-team): Do something about modified multidimensional
// arrays and clone().
Label zeroDimension = new Label();
super.visitInsn(Opcodes.DUP); // -> stack: ... origaref aref0
super.visitLdcInsn(1); // -> stack: ... origaref aref0 productTo1
for (int i = 0; i < dimCount; ++i) {
// pre: stack: ... origaref aref0 productToI
super.visitInsn(Opcodes.SWAP); // -> stack: ... origaref productToI aref
super.visitInsn(Opcodes.DUP);
Label nonNullDimension = new Label();
// -> stack: ... origaref productToI aref aref
super.visitJumpInsn(Opcodes.IFNONNULL, nonNullDimension);
// -> stack: ... origaref productToI aref
super.visitInsn(Opcodes.SWAP);
// -> stack: ... origaref aref productToI
super.visitJumpInsn(Opcodes.GOTO, zeroDimension);
super.visitLabel(nonNullDimension);
// -> stack: ... origaref productToI aref
super.visitInsn(Opcodes.DUP_X1);
// -> stack: ... origaref aref0 productToI aref
super.visitInsn(Opcodes.ARRAYLENGTH);
// -> stack: ... origaref aref0 productToI dimI
Label nonZeroDimension = new Label();
super.visitInsn(Opcodes.DUP);
// -> stack: ... origaref aref0 productToI dimI dimI
super.visitJumpInsn(Opcodes.IFNE, nonZeroDimension);
// -> stack: ... origaref aref0 productToI dimI
super.visitInsn(Opcodes.POP);
// -> stack: ... origaref aref0 productToI
super.visitJumpInsn(Opcodes.GOTO, zeroDimension);
super.visitLabel(nonZeroDimension);
// -> stack: ... origaref aref0 productToI max(dimI,1)
super.visitInsn(Opcodes.IMUL);
// -> stack: ... origaref aref0 productTo{I+1}
if (i < dimCount - 1) {
super.visitInsn(Opcodes.SWAP);
// -> stack: ... origaref productTo{I+1} aref0
super.visitInsn(Opcodes.ICONST_0);
// -> stack: ... origaref productTo{I+1} aref0 0
super.visitInsn(Opcodes.AALOAD);
// -> stack: ... origaref productTo{I+1} aref0'
super.visitInsn(Opcodes.SWAP);
}
// post: stack: ... origaref aref0 productTo{I+1}
}
super.visitLabel(zeroDimension);
super.visitInsn(Opcodes.SWAP); // -> stack: ... origaref product aref0
super.visitInsn(Opcodes.POP); // -> stack: ... origaref product
super.visitInsn(Opcodes.SWAP); // -> stack: ... product origaref
invokeRecordAllocation(typeName);
}
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
// Special case method invocations for name translation.
// Specifically to deal with methods mirrors.
String newOwner = owner;
int newOpcode = opcode;
String newDesc = translator.translateMethodDescriptor(desc);
String lookupOwner = owner;
while (lookupOwner.startsWith("[")) {
lookupOwner = lookupOwner.substring(1);
}
final Mirror mirror = translator.getMirror(lookupOwner);
if (mirror.isClassMirror()) {
newOwner = translator.translate(owner);
} else if ("<init>".equals(name)&&(opcode == Opcodes.INVOKESPECIAL)) {
/* Look for an equivalent constructor. For instance,
* INVOKESPECIAL, "java/math/BigDecimal", "<init>", "(I)V")
* will be transformed as
* INVOKESTATIC, "../BigDecimal_", "BigDecimal", "(I)Ljava/math/BigDecimal;"
*
* the previously constructed object was on top of the stack and the mirror
* function has put its result on top, so a SWAP and POP are issued to
* discard the previously constructed object and store the new one instead.
*/
String constructorDesc = newDesc.substring(0, newDesc.length()-1) + 'L' + owner + ';';
String constructorName;
int i = owner.lastIndexOf('/');
if (i == -1) {
constructorName = owner;
} else {
constructorName = owner.substring(i+1);
}
if (mirror.hasMethod(owner, constructorName, constructorDesc, Opcodes.INVOKESPECIAL)) {
newOwner = translator.translate(owner);
super.visitMethodInsn(Opcodes.INVOKESTATIC, newOwner, constructorName,
constructorDesc);
super.visitInsn(Opcodes.SWAP);
super.visitInsn(Opcodes.POP);
super.visitInsn(Opcodes.SWAP);
super.visitInsn(Opcodes.POP);
return;
}
} else if (mirror.hasMethod(owner, name, newDesc, opcode)) {
newOwner = translator.translate(owner);
newOpcode = Opcodes.INVOKESTATIC;
// We have to insert the owner into the arguments of the
// descriptor
if (opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKEINTERFACE) {
final Type[] argTypes = Type.getArgumentTypes(newDesc);
final Type[] newArgTypes = new Type[argTypes.length + 1];
newArgTypes[0] = Type.getType("L" + owner + ";");
System.arraycopy(argTypes, 0, newArgTypes, 1, argTypes.length);
newDesc = Type.getMethodDescriptor(
Type.getReturnType(newDesc), newArgTypes);
newDesc = translator.translateMethodDescriptor(newDesc);
}
}
super.visitMethodInsn(newOpcode, newOwner, name, newDesc);
}