diff --git a/src/main/java/cz/advel/stack/instrument/InstrumentMethod.java b/src/main/java/cz/advel/stack/instrument/InstrumentMethod.java index 7bc2dfe..61559ac 100644 --- a/src/main/java/cz/advel/stack/instrument/InstrumentMethod.java +++ b/src/main/java/cz/advel/stack/instrument/InstrumentMethod.java @@ -4,11 +4,11 @@ * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, + * + * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: - * + * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be @@ -37,25 +37,25 @@ * @author jezek2 */ class InstrumentMethod extends MethodNode { - + private static String STACK_NAME = Type.getInternalName(Stack.class); private static String STACK_ALLOC_CLASS_DESC = Type.getMethodDescriptor(Type.getType(Object.class), new Type[] { Type.getType(Class.class) } ); private static String STACK_ALLOC_OBJECT_DESC = Type.getMethodDescriptor(Type.getType(Object.class), new Type[] { Type.getType(Object.class) } ); private static String STATIC_ALLOC_DESC = Type.getDescriptor(StaticAlloc.class); - + // Matthias Mann's Continuations library, see: http://www.matthiasmann.de/content/view/24/26/ private static String CONTINUATIONS_SUSPEND_EXECUTION_NAME = "de/matthiasmann/continuations/SuspendExecution"; - + private Instrumenter instr; private InstrumentClass inscls; private String className; private ClassVisitor cv; - + private List frames; - + private boolean disableAllocation; private boolean staticAllocation = false; - + boolean emitMethod = true; public InstrumentMethod(int access, String name, String desc, String signature, String[] exceptions, Instrumenter instr, InstrumentClass inscls, String className, ClassVisitor cv) { @@ -64,7 +64,7 @@ public InstrumentMethod(int access, String name, String desc, String signature, this.inscls = inscls; this.className = className; this.cv = cv; - + disableAllocation = instr.isDisabled(); } @@ -78,7 +78,7 @@ public void visitEnd() { disableAllocation = true; } } - + // check for StaticAlloc annotation, if present set staticAllocation to true and remove it: if (invisibleAnnotations != null) { for (int i=0; i(Arrays.asList(analyzer.getFrames())); - + Set usedTypes = new HashSet(); boolean createStack = false; - + AbstractInsnNode insn = instructions.getFirst(); - + while (insn != null) { if (insn instanceof MethodInsnNode) { MethodInsnNode min = (MethodInsnNode)insn; - + // check for Stack.alloc(Class): if (min.owner.equals(STACK_NAME) && min.name.equals("alloc") && min.desc.equals(STACK_ALLOC_CLASS_DESC)) { AbstractInsnNode insnBefore = min.getPrevious(); Type type = null; - + + // GS: Java 8's compiler introduces LineNumberNode and LabelNode between LdcInsnNode and MethodInsnNode, skip them + if (insnBefore instanceof LineNumberNode) + insnBefore = insnBefore.getPrevious(); + if (insnBefore instanceof LabelNode) + insnBefore = insnBefore.getPrevious(); + if (insnBefore instanceof LdcInsnNode && ((LdcInsnNode)insnBefore).cst instanceof Type) { type = (Type)((LdcInsnNode)insnBefore).cst; removeInsn(insnBefore); @@ -120,15 +126,15 @@ public void visitEnd() { else { logError("first parameter of Stack.alloc(Class) must be constant"); } - + if (!staticAllocation) { usedTypes.add(type.getInternalName()); instr.addStackType(type.getInternalName()); } - + insn = replaceAllocClass(insn, type, stackVar).getNext(); removeInsn(min); - + // remove redudant checkcast: if (insn instanceof TypeInsnNode) { TypeInsnNode tin = (TypeInsnNode)insn; @@ -137,24 +143,24 @@ public void visitEnd() { removeInsn(tin); } } - + continue; } - + // check for Stack.alloc(Object): if (min.owner.equals(STACK_NAME) && min.name.equals("alloc") && min.desc.equals(STACK_ALLOC_OBJECT_DESC)) { Frame frame = frames.get(instructions.indexOf(insn)); BasicValue value = (BasicValue)frame.getStack(frame.getStackSize() - 1); Type type = value.getType(); - + if (!staticAllocation) { usedTypes.add(type.getInternalName()); instr.addStackType(type.getInternalName()); } - + insn = replaceAllocObject(insn, type, stackVar).getNext(); removeInsn(min); - + // remove redudant checkcast: if (insn instanceof TypeInsnNode) { TypeInsnNode tin = (TypeInsnNode)insn; @@ -163,10 +169,10 @@ public void visitEnd() { removeInsn(tin); } } - + continue; } - + // check for Stack.libraryCleanCurrentThread(): if (min.owner.equals(STACK_NAME) && min.name.equals("libraryCleanCurrentThread") && min.desc.equals("()V")) { if (instr.isDisabled() || instr.isSingleThread()) { @@ -182,7 +188,7 @@ public void visitEnd() { } } } - + insn = insn.getNext(); } @@ -198,7 +204,7 @@ public void visitEnd() { if (usedTypes.size() > 0) { String[] typesArray = usedTypes.toArray(new String[usedTypes.size()]); insertPush(insn, typesArray, stackVar); - + while (insn != null) { if (insn instanceof InsnNode && isReturnOpcode(insn.getOpcode())) { insertPop(insn, true, typesArray, stackVar); @@ -215,7 +221,7 @@ public void visitEnd() { tryCatchBlocks.add(new TryCatchBlockNode(startLabel, endLabel, endLabel, null)); } } - + if (emitMethod) { accept(cv); } @@ -224,61 +230,61 @@ public void visitEnd() { throw new IllegalStateException(e); } } - + //////////////////////////////////////////////////////////////////////////// - + private void removeInsn(AbstractInsnNode insn) { int idx = instructions.indexOf(insn); instructions.remove(insn); frames.remove(idx); } - + private AbstractInsnNode insertInsn(AbstractInsnNode insn, InsnList list) { if (list.size() == 0) { return insn; } - + int idx = instructions.indexOf(insn); for (int i=0; i", "()V")); - + list.add(new InsnNode(Opcodes.DUP_X1)); list.add(new InsnNode(Opcodes.SWAP)); - + Method m = StackGenerator.findGetMethodType(type.getInternalName()); list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type.getInternalName(), "set", @@ -389,10 +395,10 @@ private AbstractInsnNode replaceAllocObject(AbstractInsnNode pos, Type type, int else if (staticAllocation) { int num = inscls.registerStaticAlloc(type.getInternalName()); list.add(new FieldInsnNode(Opcodes.GETSTATIC, className, "$stackTemp"+num, type.getDescriptor())); - + list.add(new InsnNode(Opcodes.DUP_X1)); list.add(new InsnNode(Opcodes.SWAP)); - + Method m = StackGenerator.findGetMethodType(type.getInternalName()); list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type.getInternalName(), "set", @@ -405,10 +411,10 @@ else if (staticAllocation) { "get$"+Instrumenter.mangleInternalName(type.getInternalName()), "("+type.getDescriptor()+")"+type.getDescriptor())); } - + return insertInsn(pos, list); } - + private void logError(String msg) { throw new IllegalStateException(msg+" (in class "+className.replace('/', '.')+", method "+name+")"); }