From b8ee2ecdac9dda4b84d42bc9dac33b79d996c5de Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Mon, 8 Feb 2016 13:17:01 +0300 Subject: [PATCH] Support extension lambda inlining in complex stack cases (nullable receiver) --- .../kotlin/codegen/inline/MethodInliner.java | 63 +++-------------- .../codegen/inline/MethodInlinerUtil.kt | 68 +++++++++++++++++++ .../compexStack/simpleExtension.1.kt | 5 ++ .../compexStack/simpleExtension.2.kt | 5 ++ .../BlackBoxInlineCodegenTestGenerated.java | 6 ++ ...otlinAgainstInlineKotlinTestGenerated.java | 6 ++ 6 files changed, 101 insertions(+), 52 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt create mode 100644 compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt create mode 100644 compiler/testData/codegen/boxInline/compexStack/simpleExtension.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index 23e5304898f..b821c83de20 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -463,19 +463,11 @@ public class MethodInliner { LambdaInfo lambdaInfo = null; int varIndex = -1; - if (sourceValue.insns.size() == 1) { - AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); - AbstractInsnNode processingInstruction = insnNode; - - if (insnNode.getOpcode() == Opcodes.SWAP) { - processingInstruction = InlineCodegenUtil.getPrevMeaningful(insnNode); - } - lambdaInfo = getLambdaIfExistsAndMarkInstructions(processingInstruction, frame, instructionsAndFrames, toDelete); - if (lambdaInfo != null) { - //remove inlinable access - assert processingInstruction != null; - InlineCodegenUtil.removeInterval(node, processingInstruction, insnNode); - } + AbstractInsnNode insnNode = MethodInlinerUtilKt.singleOrNullInsn(sourceValue); + if (insnNode != null) { + lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions( + this, insnNode, frame, instructionsAndFrames, toDelete, true + ); } invokeCalls.add(new InvokeCall(varIndex, lambdaInfo, currentFinallyDeep)); @@ -486,12 +478,13 @@ public class MethodInliner { int offset = 0; for (int i = 0; i < paramCount; i++) { SourceValue sourceValue = frame.getStack(firstParameterIndex + i); - if (sourceValue.insns.size() == 1) { - AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); - LambdaInfo lambdaInfo = getLambdaIfExistsAndMarkInstructions(insnNode, frame, instructionsAndFrames, toDelete); + AbstractInsnNode insnNode = MethodInlinerUtilKt.singleOrNullInsn(sourceValue); + if (insnNode != null) { + LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions( + this, insnNode, frame, instructionsAndFrames, toDelete, false + ); if (lambdaInfo != null) { lambdaMapping.put(offset, lambdaInfo); - node.instructions.remove(insnNode); } } offset += i == 0 ? 1 : argTypes[i - 1].getSize(); @@ -581,41 +574,7 @@ public class MethodInliner { } @Nullable - private LambdaInfo getLambdaIfExistsAndMarkInstructions( - @Nullable AbstractInsnNode insnNode, - @NotNull Frame localFrame, - @NotNull InstructionsAndFrames insAndFrames, - @NotNull Set toDelete - ) { - LambdaInfo lambdaInfo = getLambdaIfExists(insnNode); - - if (lambdaInfo == null && insnNode instanceof VarInsnNode && insnNode.getOpcode() == Opcodes.ALOAD) { - int varIndex = ((VarInsnNode) insnNode).var; - SourceValue local = localFrame.getLocal(varIndex); - if (local.insns.size() == 1) { - AbstractInsnNode storeIns = local.insns.iterator().next(); - if (storeIns instanceof VarInsnNode && storeIns.getOpcode() == Opcodes.ASTORE) { - Frame frame = insAndFrames.get(storeIns); - if (frame != null) { - SourceValue topOfStack = frame.getStack(frame.getStackSize() - 1); - if(topOfStack.insns.size() == 1) { - AbstractInsnNode lambdaAload = topOfStack.insns.iterator().next(); - lambdaInfo = getLambdaIfExistsAndMarkInstructions(lambdaAload, frame, insAndFrames, toDelete); - if (lambdaInfo != null) { - toDelete.add(storeIns); - toDelete.add(lambdaAload); - } - } - } - } - } - } - - return lambdaInfo; - } - - @Nullable - private LambdaInfo getLambdaIfExists(@Nullable AbstractInsnNode insnNode) { + LambdaInfo getLambdaIfExists(@Nullable AbstractInsnNode insnNode) { if (insnNode == null) { return null; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt new file mode 100644 index 00000000000..975ffd3dbd6 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.inline + +import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.VarInsnNode +import org.jetbrains.org.objectweb.asm.tree.analysis.Frame +import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue + + +fun MethodInliner.getLambdaIfExistsAndMarkInstructions( + insnNode: AbstractInsnNode, + localFrame: Frame, + insAndFrames: InstructionsAndFrames, + toDelete: MutableSet, + processSwap: Boolean): LambdaInfo? { + + val processingInsnNode = if (processSwap && insnNode.opcode == Opcodes.SWAP) InlineCodegenUtil.getPrevMeaningful(insnNode) else insnNode + + var lambdaInfo = getLambdaIfExists(processingInsnNode) + + if (lambdaInfo == null && processingInsnNode is VarInsnNode && processingInsnNode.opcode == Opcodes.ALOAD) { + val varIndex = processingInsnNode.`var` + val local = localFrame.getLocal(varIndex) + val storeIns = local.singleOrNullInsn() + if (storeIns is VarInsnNode && storeIns.getOpcode() == Opcodes.ASTORE) { + val frame = insAndFrames[storeIns] + if (frame != null) { + val topOfStack = frame.getStack(frame.stackSize - 1) + val lambdaAload = topOfStack.singleOrNullInsn() + if (lambdaAload != null) { + lambdaInfo = getLambdaIfExistsAndMarkInstructions(lambdaAload, frame, insAndFrames, toDelete, processSwap) + if (lambdaInfo != null) { + toDelete.add(storeIns) + toDelete.add(lambdaAload) + } + } + } + } + } + + if (lambdaInfo != null) { + InsnSequence(processingInsnNode!!, insnNode).forEach { toDelete.add(it) } + toDelete.add(insnNode) + } + + return lambdaInfo +} + +fun SourceValue.singleOrNullInsn(): AbstractInsnNode? { + return insns.singleOrNull() +} diff --git a/compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt b/compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt new file mode 100644 index 00000000000..db5037dcde9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt @@ -0,0 +1,5 @@ +import test.* + +fun box(): String? { + return processRecords("O") { this + "K" } +} diff --git a/compiler/testData/codegen/boxInline/compexStack/simpleExtension.2.kt b/compiler/testData/codegen/boxInline/compexStack/simpleExtension.2.kt new file mode 100644 index 00000000000..278ef6cdb1d --- /dev/null +++ b/compiler/testData/codegen/boxInline/compexStack/simpleExtension.2.kt @@ -0,0 +1,5 @@ +package test + +inline fun foo(x: String) = x + +inline fun processRecords(s: String?, block: String.(String) -> String) = s?.block(foo("O")) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 10061b63f45..5fce4f5c872 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -591,6 +591,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/compexStack/simple4.1.kt"); doTestMultiFileWithInlineCheck(fileName); } + + @TestMetadata("simpleExtension.1.kt") + public void testSimpleExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/complex") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 81168d7f138..7a458453691 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -591,6 +591,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/compexStack/simple4.1.kt"); doBoxTestWithInlineCheck(fileName); } + + @TestMetadata("simpleExtension.1.kt") + public void testSimpleExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/compexStack/simpleExtension.1.kt"); + doBoxTestWithInlineCheck(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/complex")