diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt new file mode 100644 index 00000000000..5e0888930c4 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/GlobalInlineContext.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen.inline + +import org.jetbrains.kotlin.codegen.InlineCycleReporter +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import java.util.* + +class GlobalInlineContext(diagnostics: DiagnosticSink) { + + private val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics) + + private val typesUsedInInlineFunctions = LinkedList>() + + fun enterIntoInlining(call: ResolvedCall<*>?) = + inlineCycleReporter.enterIntoInlining(call).also { + if (it) typesUsedInInlineFunctions.push(hashSetOf()) + } + + fun exitFromInliningOf(call: ResolvedCall<*>?) { + inlineCycleReporter.exitFromInliningOf(call) + val pop = typesUsedInInlineFunctions.pop() + typesUsedInInlineFunctions.peek()?.addAll(pop) + } + + fun recordTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().add(type) + + fun isTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().contains(type) +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 3ed985b917f..63503444b4c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -652,14 +652,14 @@ class PsiInlineCodegen( callDefault: Boolean, codegen: ExpressionCodegen ) { - if (!state.inlineCycleReporter.enterIntoInlining(resolvedCall)) { + if (!state.globalInlineContext.enterIntoInlining(resolvedCall)) { generateStub(resolvedCall, codegen) return } try { performInline(resolvedCall?.typeArguments, callDefault, codegen) } finally { - state.inlineCycleReporter.exitFromInliningOf(resolvedCall) + state.globalInlineContext.exitFromInliningOf(resolvedCall) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 866331133cc..de00e7c03ff 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -62,6 +62,13 @@ class MethodInliner( return doInline(adapter, remapper, remapReturn, labelOwner, 0) } + private fun recordTransformation(info: TransformationInfo) { + if (!inliningContext.isInliningLambda) { + inliningContext.root.state.globalInlineContext.recordTypeFromInlineFunction(info.oldClassName) + } + transformations.add(info) + } + private fun doInline( adapter: MethodVisitor, remapper: LocalVarRemapper, @@ -160,7 +167,9 @@ class MethodInliner( if (inliningContext.isInliningLambda && inliningContext.lambdaInfo !is DefaultLambda && //never delete default lambda classes - transformationInfo!!.canRemoveAfterTransformation()) { + transformationInfo!!.canRemoveAfterTransformation() && + !inliningContext.root.state.globalInlineContext.isTypeFromInlineFunction(oldClassName) + ) { // this class is transformed and original not used so we should remove original one after inlining result.addClassToRemove(oldClassName) } @@ -452,7 +461,7 @@ class MethodInliner( invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep)) } else if (isSamWrapperConstructorCall(owner, name)) { - transformations.add(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner))) + recordTransformation(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner))) } else if (isAnonymousConstructorCall(owner, name)) { val lambdaMapping = HashMap() @@ -473,7 +482,7 @@ class MethodInliner( offset += if (i == 0) 1 else argTypes[i - 1].size } - transformations.add( + recordTransformation( buildConstructorInvocation( owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated ) @@ -491,7 +500,7 @@ class MethodInliner( val fieldInsnNode = cur as FieldInsnNode? val className = fieldInsnNode!!.owner if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) { - transformations.add( + recordTransformation( AnonymousObjectTransformationInfo( className, awaitClassReification, isAlreadyRegenerated(className), true, inliningContext.nameGenerator @@ -500,7 +509,7 @@ class MethodInliner( awaitClassReification = false } else if (isWhenMappingAccess(className, fieldInsnNode.name)) { - transformations.add( + recordTransformation( WhenMappingTransformationInfo( className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode ) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 1c6ee94f9ec..4a5e59dc3b4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.context.RootContext import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension +import org.jetbrains.kotlin.codegen.inline.GlobalInlineContext import org.jetbrains.kotlin.codegen.inline.InlineCache import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory @@ -196,7 +197,7 @@ class GenerationState private constructor( IntrinsicMethods(target, shouldUseConsistentEquals) } val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this) - val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics) + val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics) val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this) val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(module) val factory: ClassFileFactory diff --git a/compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt b/compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt new file mode 100644 index 00000000000..be7f1378341 --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt @@ -0,0 +1,41 @@ +//WITH_RUNTIME +// FILE: 1.kt +class Foo { + var bar = "" + + inline fun ifNotBusyPerform(action: (complete: () -> Unit) -> Unit) { + action { + bar += "K" + } + } + + fun ifNotBusySayHello() { + ifNotBusyPerform { + bar += "O" + it() + } + } + + inline fun inlineFun(s: () -> Unit) { + s() + } + + fun start() { + inlineFun { + { + ifNotBusyPerform { + ifNotBusySayHello() + } + }() + } + } +} + +// FILE: 2.kt + +fun box(): String { + val foo = Foo() + foo.start() + + return foo.bar +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inline/deleteClassOnTransfromation.kt b/compiler/testData/codegen/bytecodeText/inline/deleteClassOnTransfromation.kt new file mode 100644 index 00000000000..da22cde67a7 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/deleteClassOnTransfromation.kt @@ -0,0 +1,19 @@ +fun test() { + { + {}() + }() +} + +inline fun ifun(s: () -> Unit) { + s() +} + +fun test2() { + var z = 1; + ifun { + { z = 2 }() + } +} + +// 1 class DeleteClassOnTransfromationKt\$test\$1\$1 +// 0 class DeleteClassOnTransfromationKt\$test2\$1\$1 \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 8b760c99d17..fa25b02bf9d 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -201,6 +201,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli doTest(fileName); } + @TestMetadata("kt19399.kt") + public void testKt19399() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt"); + doTest(fileName); + } + @TestMetadata("kt19434.kt") public void testKt19434() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt"); diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 55b6f74f764..fefb2869940 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -201,6 +201,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC doTest(fileName); } + @TestMetadata("kt19399.kt") + public void testKt19399() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt"); + doTest(fileName); + } + @TestMetadata("kt19434.kt") public void testKt19434() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 12ed9bf1c5a..3eb727e2f64 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -201,6 +201,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTest(fileName); } + @TestMetadata("kt19399.kt") + public void testKt19399() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt"); + doTest(fileName); + } + @TestMetadata("kt19434.kt") public void testKt19434() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 0e3ff8b45f8..79368b61011 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1821,6 +1821,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("deleteClassOnTransfromation.kt") + public void testDeleteClassOnTransfromation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/deleteClassOnTransfromation.kt"); + doTest(fileName); + } + @TestMetadata("finallyMarkers.kt") public void testFinallyMarkers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/finallyMarkers.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index b7c30746f0a..dafd30265a7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -201,6 +201,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doTest(fileName); } + @TestMetadata("kt19399.kt") + public void testKt19399() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt"); + doTest(fileName); + } + @TestMetadata("kt19434.kt") public void testKt19434() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");