diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/MixinApplicatorStandard.java b/src/main/java/org/spongepowered/asm/mixin/transformer/MixinApplicatorStandard.java index 8251b25b3..1cae9f681 100644 --- a/src/main/java/org/spongepowered/asm/mixin/transformer/MixinApplicatorStandard.java +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/MixinApplicatorStandard.java @@ -745,19 +745,31 @@ protected final void appendInsns(MixinTargetContext mixin, MethodNode method) { MethodNode target = this.findTargetMethod(method); if (target != null) { - AbstractInsnNode returnNode = Bytecode.findInsn(target, Opcodes.RETURN); - - if (returnNode != null) { + List returnNodes = Bytecode.findAllInsns(target, Opcodes.RETURN); + if (!returnNodes.isEmpty()) { + // Replace all existing return instructions with a GOTO to the start of the newly appended code + LabelNode appendedCodeStartLabel = new LabelNode(); + for (AbstractInsnNode returnNode : returnNodes) { + target.instructions.set(returnNode, new JumpInsnNode(Opcodes.GOTO, appendedCodeStartLabel)); + } + target.instructions.add(appendedCodeStartLabel); + + // Append all the new code to the end of the target method, excluding line numbers Iterator injectIter = method.instructions.iterator(); while (injectIter.hasNext()) { AbstractInsnNode insn = injectIter.next(); - if (!(insn instanceof LineNumberNode) && insn.getOpcode() != Opcodes.RETURN) { - target.instructions.insertBefore(returnNode, insn); + if (!(insn instanceof LineNumberNode)) { + injectIter.remove(); + target.instructions.add(insn); } } target.maxLocals = Math.max(target.maxLocals, method.maxLocals); target.maxStack = Math.max(target.maxStack, method.maxStack); + + // Merge incoming try-catch blocks into the target method + target.tryCatchBlocks.addAll(method.tryCatchBlocks); + // We could probably copy over local variable information as well? } return; diff --git a/src/main/java/org/spongepowered/asm/util/Bytecode.java b/src/main/java/org/spongepowered/asm/util/Bytecode.java index d2544c416..f217de2fb 100644 --- a/src/main/java/org/spongepowered/asm/util/Bytecode.java +++ b/src/main/java/org/spongepowered/asm/util/Bytecode.java @@ -285,9 +285,9 @@ public static MethodNode findMethod(ClassNode classNode, String name, String des * @return found node or null if not found */ public static AbstractInsnNode findInsn(MethodNode method, int opcode) { - Iterator findReturnIter = method.instructions.iterator(); - while (findReturnIter.hasNext()) { - AbstractInsnNode insn = findReturnIter.next(); + Iterator findInsnIter = method.instructions.iterator(); + while (findInsnIter.hasNext()) { + AbstractInsnNode insn = findInsnIter.next(); if (insn.getOpcode() == opcode) { return insn; } @@ -295,6 +295,25 @@ public static AbstractInsnNode findInsn(MethodNode method, int opcode) { return null; } + /** + * Find all insn nodes with a matching opcode in the specified method + * + * @param method method to search + * @param opcode opcode to search for + * @return a list containing the found nodes, may be empty if not found + */ + public static List findAllInsns(MethodNode method, int opcode) { + List insns = new ArrayList(); + Iterator findInsnIter = method.instructions.iterator(); + while (findInsnIter.hasNext()) { + AbstractInsnNode insn = findInsnIter.next(); + if (insn.getOpcode() == opcode) { + insns.add(insn); + } + } + return insns; + } + /** * Find the call to super() or this() in a constructor. * This attempts to locate the first call to <init> which