@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; }
private static void removeClosureAssertions(MethodNode node) { AbstractInsnNode cur = node.instructions.getFirst(); while (cur != null && cur.getNext() != null) { AbstractInsnNode next = cur.getNext(); if (next.getType() == AbstractInsnNode.METHOD_INSN) { MethodInsnNode methodInsnNode = (MethodInsnNode) next; if (methodInsnNode.name.equals("checkParameterIsNotNull") && methodInsnNode.owner.equals(IntrinsicMethods.INTRINSICS_CLASS_NAME)) { AbstractInsnNode prev = cur.getPrevious(); assert cur.getOpcode() == Opcodes.LDC : "checkParameterIsNotNull should go after LDC but " + cur; assert prev.getOpcode() == Opcodes.ALOAD : "checkParameterIsNotNull should be invoked on local var but " + prev; node.instructions.remove(prev); node.instructions.remove(cur); cur = next.getNext(); node.instructions.remove(next); next = cur; } } cur = next; } }
private static boolean isEmptyTryInterval(@NotNull TryCatchBlockNode tryCatchBlockNode) { LabelNode start = tryCatchBlockNode.start; AbstractInsnNode end = tryCatchBlockNode.end; while (end != start && end instanceof LabelNode) { end = end.getPrevious(); } return start == end; }
// marked return could be either non-local or local in case of labeled lambda self-returns public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) { if (!isReturnOpcode(returnIns.getOpcode())) { return false; } AbstractInsnNode globalFlag = returnIns.getPrevious(); return globalFlag instanceof MethodInsnNode && NON_LOCAL_RETURN.equals(((MethodInsnNode) globalFlag).owner); }
@Override public AnnotationVisitor visitInsnAnnotation( int typeRef, TypePath typePath, String desc, boolean visible) { // Finds the last real instruction, i.e. the instruction targeted by // this annotation. AbstractInsnNode insn = instructions.getLast(); while (insn.getOpcode() == -1) { insn = insn.getPrevious(); } // Adds the annotation to this instruction. TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc); if (visible) { if (insn.visibleTypeAnnotations == null) { insn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1); } insn.visibleTypeAnnotations.add(an); } else { if (insn.invisibleTypeAnnotations == null) { insn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1); } insn.invisibleTypeAnnotations.add(an); } return an; }