From 07bde889b4fa7b40bb7e3b8737093ef18713eb2d Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 30 Aug 2019 09:45:34 +0200 Subject: [PATCH] JVM_IR: generate more correct names for regenerated objects and fake lambda types, too. (But those only matter for debugging.) Also, share object name generators between methods with the same name to avoid rewriting objects from one with objects from the other. --- .../kotlin/backend/jvm/JvmBackendContext.kt | 9 +++++++++ .../backend/jvm/codegen/ClassCodegen.kt | 9 +++++++++ .../backend/jvm/codegen/ExpressionCodegen.kt | 2 +- .../backend/jvm/codegen/IrInlineCodegen.kt | 13 ++++++++----- ....kt => InlineCallableReferenceToLambda.kt} | 14 ++++++++------ .../regeneratedLambdaName.kt | 2 -- .../regeneratedLambdaName2.kt | 19 +++++++++++++++++++ .../lambdaTransformation/sameCaptured.kt | 2 -- .../BlackBoxInlineCodegenTestGenerated.java | 5 +++++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++++ .../IrBlackBoxInlineCodegenTestGenerated.java | 5 +++++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++++ 12 files changed, 74 insertions(+), 16 deletions(-) rename compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/{InlineCallableRefereceToLambda.kt => InlineCallableReferenceToLambda.kt} (97%) create mode 100644 compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index fda7910d093..3f1706e47ff 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.MemoizedInlineClassReplacements import org.jetbrains.kotlin.codegen.ClassBuilder +import org.jetbrains.kotlin.codegen.inline.NameGenerator import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.jvm.JvmClassName @@ -71,6 +73,13 @@ class JvmBackendContext( localClassInfo[container.attributeOwnerId] = value } + // TODO cache these at ClassCodegen level. Currently, sharing this map between classes in a module is required + // because IrSourceCompilerForInline constructs a new (Fake)ClassCodegen for every call to + // an inline function in the same module. Thus, if two inline functions happen to have the same name + // and call a third inline function that has an anonymous object, the one which is called last + // will overwrite the other's regenerated copy. (Or don't recompile the inline function for every call.) + internal val regeneratedObjectNameGenerators = mutableMapOf, NameGenerator>() + internal val localDelegatedProperties = mutableMapOf>() internal val multifileFacadesToAdd = mutableMapOf>() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index cda623491ac..53665297b12 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.constantValue import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper +import org.jetbrains.kotlin.codegen.inline.NameGenerator import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages import org.jetbrains.kotlin.codegen.inline.SourceMapper import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME @@ -82,6 +84,13 @@ open class ClassCodegen protected constructor( else -> null } + fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator { + val name = if (function.name.isSpecial) Name.identifier("special") else function.name + return context.regeneratedObjectNameGenerators.getOrPut(irClass to name) { + NameGenerator("${type.internalName}\$$name\$\$inlined") + } + } + fun generate(): ReifiedTypeParametersUsages { if (withinInline) { getOrCreateSourceMapper() //initialize default mapping that would be later written in class file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index e87a6679828..c9100684e58 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -116,7 +116,7 @@ class ExpressionCodegen( override val visitor: InstructionAdapter get() = mv - override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo") // TODO + override val inlineNameGenerator: NameGenerator = classCodegen.getRegeneratedObjectNameGenerator(irFunction) override val typeSystem: TypeSystemCommonBackendContext get() = typeMapper.typeSystem diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index e07aa6e0bff..a9e4e3cab74 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -151,11 +151,14 @@ class IrExpressionLambdaImpl( return false //always false } - companion object { - private var counter: Int = 123//TODO: pass proper type - } - - override val lambdaClassType: Type = Type.getObjectType("test${counter++}") + // This name doesn't actually matter: it is used internally to tell this lambda's captured + // arguments apart from any other scope's. So long as it's unique, any value is fine. + // This particular string slightly aids in debugging internal compiler errors as it at least + // points towards the function containing the lambda. + override val lambdaClassType: Type = Type.getObjectType( + context.getLocalClassInfo(reference)?.internalName + ?: throw AssertionError("callable reference ${reference.dump()} has no name in context") + ) override val capturedVars: List = arrayListOf().apply { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableRefereceToLambda.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt similarity index 97% rename from compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableRefereceToLambda.kt rename to compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt index a17fe244252..2c3ddc59581 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableRefereceToLambda.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt @@ -24,10 +24,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildFun -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.util.defaultType @@ -51,6 +48,7 @@ internal val inlineCallableReferenceToLambdaPhase = makeIrFilePhase( // internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendContext) : FileLoweringPass { private val inlinableCR = mutableSetOf() + override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { @@ -118,7 +116,9 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte expression.startOffset, expression.endOffset, field.type, newLambda.symbol, newLambda.symbol.descriptor, 0, IrStatementOrigin.LAMBDA - ) + ).apply { + copyAttributes(expression) + } } } @@ -209,7 +209,9 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte expression.startOffset, expression.endOffset, referencedFunction.returnType, newLambda.symbol, newLambda.symbol.descriptor, referencedFunction.typeParameters.size, IrStatementOrigin.LAMBDA - ) + ).apply { + copyAttributes(expression) + } } } } \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt b/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt index 5a0b800ab50..80e630ccc3b 100644 --- a/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt +++ b/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt b/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt new file mode 100644 index 00000000000..8c011de82e3 --- /dev/null +++ b/compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt +package test + +inline fun call(crossinline f: () -> R) : R { + return { f() }() +} + +// FILE: 2.kt +//NO_CHECK_LAMBDA_INLINING +import test.* + +inline fun sameName(s: Long): String = call { "FAIL" } +inline fun sameName(s: Int): String = call { "OK" } + +fun box(): String { + val result = sameName(1) + sameName(1L) + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt b/compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt index ae452746e05..3cdd3687bf2 100644 --- a/compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt +++ b/compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: 1.kt package test diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index dbf5664efca..9e4fddaf99b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -1888,6 +1888,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); } + @TestMetadata("regeneratedLambdaName2.kt") + public void testRegeneratedLambdaName2() throws Exception { + runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt"); + } + @TestMetadata("sameCaptured.kt") public void testSameCaptured() throws Exception { runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 997413d51fb..ac8ba7c6560 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1888,6 +1888,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); } + @TestMetadata("regeneratedLambdaName2.kt") + public void testRegeneratedLambdaName2() throws Exception { + runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt"); + } + @TestMetadata("sameCaptured.kt") public void testSameCaptured() throws Exception { runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 98712a626fd..b56c3ea364a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -1888,6 +1888,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); } + @TestMetadata("regeneratedLambdaName2.kt") + public void testRegeneratedLambdaName2() throws Exception { + runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt"); + } + @TestMetadata("sameCaptured.kt") public void testSameCaptured() throws Exception { runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 394e3e6df72..95295dd2b22 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1888,6 +1888,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName.kt"); } + @TestMetadata("regeneratedLambdaName2.kt") + public void testRegeneratedLambdaName2() throws Exception { + runTest("compiler/testData/codegen/boxInline/lambdaTransformation/regeneratedLambdaName2.kt"); + } + @TestMetadata("sameCaptured.kt") public void testSameCaptured() throws Exception { runTest("compiler/testData/codegen/boxInline/lambdaTransformation/sameCaptured.kt");