Never delete types from inline functions during inline transformations

#KT-19399 Fixed
This commit is contained in:
Mikhael Bogdanov
2018-02-15 16:39:08 +01:00
parent 729c866f47
commit d732f0e160
11 changed files with 141 additions and 8 deletions
@@ -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<MutableSet<String>>()
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)
}
@@ -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)
}
}
@@ -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<Int, LambdaInfo>()
@@ -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
)
@@ -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
@@ -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
}
@@ -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
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");