@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; }
// TODO: check it's external module // TODO?: assert method exists in facade? public String changeOwnerForExternalPackage(String type, int opcode) { if (isSameModule || (opcode & Opcodes.INVOKESTATIC) == 0) { return type; } JvmClassName name = JvmClassName.byInternalName(type); String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(name.getPackageFqName()); if (type.startsWith(packageClassInternalName + '$')) { VirtualFile virtualFile = InlineCodegenUtil.findVirtualFile(inliningContext.state.getProject(), type); if (virtualFile != null) { KotlinJvmBinaryClass klass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile); if (klass != null && klass.getClassHeader().getSyntheticClassKind() == KotlinSyntheticClass.Kind.PACKAGE_PART) { return packageClassInternalName; } } } return type; }