Skip to content

Commit d083c5e

Browse files
committed
Copy try-catch blocks when merging static initializers
This also causes the merged method to work as expected if the target method contains more than one RETURN instruction.
1 parent 155314e commit d083c5e

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

src/main/java/org/spongepowered/asm/mixin/transformer/MixinApplicatorStandard.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -745,19 +745,31 @@ protected final void appendInsns(MixinTargetContext mixin, MethodNode method) {
745745
MethodNode target = this.findTargetMethod(method);
746746

747747
if (target != null) {
748-
AbstractInsnNode returnNode = Bytecode.findInsn(target, Opcodes.RETURN);
749-
750-
if (returnNode != null) {
748+
List<AbstractInsnNode> returnNodes = Bytecode.findAllInsns(target, Opcodes.RETURN);
749+
if (!returnNodes.isEmpty()) {
750+
// Replace all existing return instructions with a GOTO to the start of the newly appended code
751+
LabelNode appendedCodeStartLabel = new LabelNode();
752+
for (AbstractInsnNode returnNode : returnNodes) {
753+
method.instructions.set(returnNode, new JumpInsnNode(Opcodes.GOTO, appendedCodeStartLabel));
754+
}
755+
method.instructions.add(appendedCodeStartLabel);
756+
757+
// Append all the new code to the end of the target method, excluding line numbers
751758
Iterator<AbstractInsnNode> injectIter = method.instructions.iterator();
752759
while (injectIter.hasNext()) {
753760
AbstractInsnNode insn = injectIter.next();
754-
if (!(insn instanceof LineNumberNode) && insn.getOpcode() != Opcodes.RETURN) {
755-
target.instructions.insertBefore(returnNode, insn);
761+
if (!(insn instanceof LineNumberNode)) {
762+
injectIter.remove();
763+
target.instructions.add(insn);
756764
}
757765
}
758766

759767
target.maxLocals = Math.max(target.maxLocals, method.maxLocals);
760768
target.maxStack = Math.max(target.maxStack, method.maxStack);
769+
770+
// Merge incoming try-catch blocks into the target method
771+
target.tryCatchBlocks.addAll(method.tryCatchBlocks);
772+
// We could probably copy over local variable information as well?
761773
}
762774

763775
return;

src/main/java/org/spongepowered/asm/util/Bytecode.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -285,16 +285,35 @@ public static MethodNode findMethod(ClassNode classNode, String name, String des
285285
* @return found node or null if not found
286286
*/
287287
public static AbstractInsnNode findInsn(MethodNode method, int opcode) {
288-
Iterator<AbstractInsnNode> findReturnIter = method.instructions.iterator();
289-
while (findReturnIter.hasNext()) {
290-
AbstractInsnNode insn = findReturnIter.next();
288+
Iterator<AbstractInsnNode> findInsnIter = method.instructions.iterator();
289+
while (findInsnIter.hasNext()) {
290+
AbstractInsnNode insn = findInsnIter.next();
291291
if (insn.getOpcode() == opcode) {
292292
return insn;
293293
}
294294
}
295295
return null;
296296
}
297297

298+
/**
299+
* Find all insn nodes with a matching opcode in the specified method
300+
*
301+
* @param method method to search
302+
* @param opcode opcode to search for
303+
* @return a list containing the found nodes, may be empty if not found
304+
*/
305+
public static List<AbstractInsnNode> findAllInsns(MethodNode method, int opcode) {
306+
List<AbstractInsnNode> insns = new ArrayList<AbstractInsnNode>();
307+
Iterator<AbstractInsnNode> findInsnIter = method.instructions.iterator();
308+
while (findInsnIter.hasNext()) {
309+
AbstractInsnNode insn = findInsnIter.next();
310+
if (insn.getOpcode() == opcode) {
311+
insns.add(insn);
312+
}
313+
}
314+
return insns;
315+
}
316+
298317
/**
299318
* Find the call to <tt>super()</tt> or <tt>this()</tt> in a constructor.
300319
* This attempts to locate the first call to <tt>&lt;init&gt;</tt> which

0 commit comments

Comments
 (0)