@NotNull // process local and global returns (local substituted with goto end-label global kept unchanged) public static List<PointForExternalFinallyBlocks> processReturns( @NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) { if (!remapReturn) { return Collections.emptyList(); } List<PointForExternalFinallyBlocks> result = new ArrayList<PointForExternalFinallyBlocks>(); InsnList instructions = node.instructions; AbstractInsnNode insnNode = instructions.getFirst(); while (insnNode != null) { if (InlineCodegenUtil.isReturnOpcode(insnNode.getOpcode())) { AbstractInsnNode previous = insnNode.getPrevious(); MethodInsnNode flagNode; boolean isLocalReturn = true; String labelName = null; if (previous != null && previous instanceof MethodInsnNode && InlineCodegenUtil.NON_LOCAL_RETURN.equals(((MethodInsnNode) previous).owner)) { flagNode = (MethodInsnNode) previous; labelName = flagNode.name; } if (labelName != null) { isLocalReturn = labelOwner.isMyLabel(labelName); // remove global return flag if (isLocalReturn) { instructions.remove(previous); } } if (isLocalReturn && endLabel != null) { LabelNode labelNode = (LabelNode) endLabel.info; JumpInsnNode jumpInsnNode = new JumpInsnNode(Opcodes.GOTO, labelNode); instructions.insert(insnNode, jumpInsnNode); instructions.remove(insnNode); insnNode = jumpInsnNode; } // genetate finally block before nonLocalReturn flag/return/goto result.add( new PointForExternalFinallyBlocks( isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode()))); } insnNode = insnNode.getNext(); } return result; }
public InlineResult doInline( @NotNull MethodVisitor adapter, @NotNull LocalVarRemapper remapper, boolean remapReturn, @NotNull LabelOwner labelOwner) { // analyze body MethodNode transformedNode = markPlacesForInlineAndRemoveInlinable(node); // substitute returns with "goto end" instruction to keep non local returns in lambdas Label end = new Label(); transformedNode = doInline(transformedNode); removeClosureAssertions(transformedNode); InsnList instructions = transformedNode.instructions; instructions.resetLabels(); MethodNode resultNode = new MethodNode( InlineCodegenUtil.API, transformedNode.access, transformedNode.name, transformedNode.desc, transformedNode.signature, ArrayUtil.toStringArray(transformedNode.exceptions)); RemapVisitor visitor = new RemapVisitor(resultNode, remapper, nodeRemapper); try { transformedNode.accept(visitor); } catch (Exception e) { throw wrapException(e, transformedNode, "couldn't inline method call"); } resultNode.visitLabel(end); if (inliningContext.isRoot()) { InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks); } processReturns(resultNode, labelOwner, remapReturn, end); // flush transformed node to output resultNode.accept(new InliningInstructionAdapter(adapter)); return result; }