Never delete types from inline functions during inline transformations
#KT-19399 Fixed
This commit is contained in:
@@ -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,
|
callDefault: Boolean,
|
||||||
codegen: ExpressionCodegen
|
codegen: ExpressionCodegen
|
||||||
) {
|
) {
|
||||||
if (!state.inlineCycleReporter.enterIntoInlining(resolvedCall)) {
|
if (!state.globalInlineContext.enterIntoInlining(resolvedCall)) {
|
||||||
generateStub(resolvedCall, codegen)
|
generateStub(resolvedCall, codegen)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
performInline(resolvedCall?.typeArguments, callDefault, codegen)
|
performInline(resolvedCall?.typeArguments, callDefault, codegen)
|
||||||
} finally {
|
} finally {
|
||||||
state.inlineCycleReporter.exitFromInliningOf(resolvedCall)
|
state.globalInlineContext.exitFromInliningOf(resolvedCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ class MethodInliner(
|
|||||||
return doInline(adapter, remapper, remapReturn, labelOwner, 0)
|
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(
|
private fun doInline(
|
||||||
adapter: MethodVisitor,
|
adapter: MethodVisitor,
|
||||||
remapper: LocalVarRemapper,
|
remapper: LocalVarRemapper,
|
||||||
@@ -160,7 +167,9 @@ class MethodInliner(
|
|||||||
|
|
||||||
if (inliningContext.isInliningLambda &&
|
if (inliningContext.isInliningLambda &&
|
||||||
inliningContext.lambdaInfo !is DefaultLambda && //never delete default lambda classes
|
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
|
// this class is transformed and original not used so we should remove original one after inlining
|
||||||
result.addClassToRemove(oldClassName)
|
result.addClassToRemove(oldClassName)
|
||||||
}
|
}
|
||||||
@@ -452,7 +461,7 @@ class MethodInliner(
|
|||||||
invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep))
|
invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep))
|
||||||
}
|
}
|
||||||
else if (isSamWrapperConstructorCall(owner, name)) {
|
else if (isSamWrapperConstructorCall(owner, name)) {
|
||||||
transformations.add(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner)))
|
recordTransformation(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner)))
|
||||||
}
|
}
|
||||||
else if (isAnonymousConstructorCall(owner, name)) {
|
else if (isAnonymousConstructorCall(owner, name)) {
|
||||||
val lambdaMapping = HashMap<Int, LambdaInfo>()
|
val lambdaMapping = HashMap<Int, LambdaInfo>()
|
||||||
@@ -473,7 +482,7 @@ class MethodInliner(
|
|||||||
offset += if (i == 0) 1 else argTypes[i - 1].size
|
offset += if (i == 0) 1 else argTypes[i - 1].size
|
||||||
}
|
}
|
||||||
|
|
||||||
transformations.add(
|
recordTransformation(
|
||||||
buildConstructorInvocation(
|
buildConstructorInvocation(
|
||||||
owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||||
)
|
)
|
||||||
@@ -491,7 +500,7 @@ class MethodInliner(
|
|||||||
val fieldInsnNode = cur as FieldInsnNode?
|
val fieldInsnNode = cur as FieldInsnNode?
|
||||||
val className = fieldInsnNode!!.owner
|
val className = fieldInsnNode!!.owner
|
||||||
if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) {
|
if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) {
|
||||||
transformations.add(
|
recordTransformation(
|
||||||
AnonymousObjectTransformationInfo(
|
AnonymousObjectTransformationInfo(
|
||||||
className, awaitClassReification, isAlreadyRegenerated(className), true,
|
className, awaitClassReification, isAlreadyRegenerated(className), true,
|
||||||
inliningContext.nameGenerator
|
inliningContext.nameGenerator
|
||||||
@@ -500,7 +509,7 @@ class MethodInliner(
|
|||||||
awaitClassReification = false
|
awaitClassReification = false
|
||||||
}
|
}
|
||||||
else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
||||||
transformations.add(
|
recordTransformation(
|
||||||
WhenMappingTransformationInfo(
|
WhenMappingTransformationInfo(
|
||||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
|
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.CodegenContext
|
||||||
import org.jetbrains.kotlin.codegen.context.RootContext
|
import org.jetbrains.kotlin.codegen.context.RootContext
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
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.inline.InlineCache
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
|
import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
|
||||||
@@ -196,7 +197,7 @@ class GenerationState private constructor(
|
|||||||
IntrinsicMethods(target, shouldUseConsistentEquals)
|
IntrinsicMethods(target, shouldUseConsistentEquals)
|
||||||
}
|
}
|
||||||
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
|
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
|
||||||
val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
|
val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics)
|
||||||
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
|
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
|
||||||
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(module)
|
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(module)
|
||||||
val factory: ClassFileFactory
|
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
|
||||||
+6
@@ -201,6 +201,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt19434.kt")
|
||||||
public void testKt19434() throws Exception {
|
public void testKt19434() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||||
|
|||||||
+6
@@ -201,6 +201,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt19434.kt")
|
||||||
public void testKt19434() throws Exception {
|
public void testKt19434() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||||
|
|||||||
+6
@@ -201,6 +201,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt19434.kt")
|
||||||
public void testKt19434() throws Exception {
|
public void testKt19434() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
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);
|
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")
|
@TestMetadata("finallyMarkers.kt")
|
||||||
public void testFinallyMarkers() throws Exception {
|
public void testFinallyMarkers() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/finallyMarkers.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/finallyMarkers.kt");
|
||||||
|
|||||||
Generated
+6
@@ -201,6 +201,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt19434.kt")
|
||||||
public void testKt19434() throws Exception {
|
public void testKt19434() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user