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; } }
@NotNull protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) { node = prepareNode(node); Analyzer<SourceValue> analyzer = new Analyzer<SourceValue>(new SourceInterpreter()) { @NotNull @Override protected Frame<SourceValue> newFrame(int nLocals, int nStack) { return new Frame<SourceValue>(nLocals, nStack) { @Override public void execute( @NotNull AbstractInsnNode insn, Interpreter<SourceValue> interpreter) throws AnalyzerException { if (insn.getOpcode() == Opcodes.RETURN) { // there is exception on void non local return in frame return; } super.execute(insn, interpreter); } }; } }; Frame<SourceValue>[] sources; try { sources = analyzer.analyze("fake", node); } catch (AnalyzerException e) { throw wrapException(e, node, "couldn't inline method call"); } AbstractInsnNode cur = node.instructions.getFirst(); int index = 0; boolean awaitClassReification = false; Set<LabelNode> possibleDeadLabels = new HashSet<LabelNode>(); while (cur != null) { Frame<SourceValue> frame = sources[index]; if (frame != null) { if (ReifiedTypeInliner.isNeedClassReificationMarker(cur)) { awaitClassReification = true; } else if (cur.getType() == AbstractInsnNode.METHOD_INSN) { MethodInsnNode methodInsnNode = (MethodInsnNode) cur; String owner = methodInsnNode.owner; String desc = methodInsnNode.desc; String name = methodInsnNode.name; // TODO check closure int paramLength = Type.getArgumentTypes(desc).length + 1; // non static if (isInvokeOnLambda(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength); LambdaInfo lambdaInfo = null; int varIndex = -1; if (sourceValue.insns.size() == 1) { AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); lambdaInfo = getLambdaIfExists(insnNode); if (lambdaInfo != null) { // remove inlinable access node.instructions.remove(insnNode); } } invokeCalls.add(new InvokeCall(varIndex, lambdaInfo)); } else if (isAnonymousConstructorCall(owner, name)) { Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>(); int paramStart = frame.getStackSize() - paramLength; for (int i = 0; i < paramLength; i++) { SourceValue sourceValue = frame.getStack(paramStart + i); if (sourceValue.insns.size() == 1) { AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); LambdaInfo lambdaInfo = getLambdaIfExists(insnNode); if (lambdaInfo != null) { lambdaMapping.put(i, lambdaInfo); node.instructions.remove(insnNode); } } } anonymousObjectGenerations.add( buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification)); awaitClassReification = false; } } else if (cur.getOpcode() == Opcodes.GETSTATIC) { FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; String owner = fieldInsnNode.owner; if (isAnonymousSingletonLoad(owner, fieldInsnNode.name)) { anonymousObjectGenerations.add( new AnonymousObjectGeneration( owner, isSameModule, awaitClassReification, isAlreadyRegenerated(owner), true)); awaitClassReification = false; } } } AbstractInsnNode prevNode = cur; cur = cur.getNext(); index++; // given frame is <tt>null</tt> if and only if the corresponding instruction cannot be reached // (dead code). if (frame == null) { // clean dead code otherwise there is problems in unreachable finally block, don't touch // label it cause try/catch/finally problems if (prevNode.getType() == AbstractInsnNode.LABEL) { // NB: Cause we generate exception table for default handler using gaps (see // ExpressionCodegen.visitTryExpression) // it may occurs that interval for default handler starts before catch start label, so // this label seems as dead, // but as result all this labels will be merged into one (see KT-5863) } else { node.instructions.remove(prevNode); } } } // clean dead try/catch blocks List<TryCatchBlockNode> blocks = node.tryCatchBlocks; for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) { TryCatchBlockNode block = iterator.next(); if (isEmptyTryInterval(block)) { iterator.remove(); } } return node; }