From 6ecda9e8afd9be5a733898816f6933fe09ea15ad Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Fri, 31 Jan 2020 14:22:37 +0300 Subject: [PATCH] [IR] [JVM_IR] Commonized SAM conversions lowering --- .../lower/SingleAbstractMethodLowering.kt | 37 ++++++++----------- .../kotlin/backend/jvm/DeclarationOrigins.kt | 1 - .../lower/JvmSingleAbstractMethodLowering.kt | 28 ++++++++++++++ .../ir/declarations/IrDeclarationOrigin.kt | 2 + 4 files changed, 46 insertions(+), 22 deletions(-) rename compiler/ir/{backend.jvm/src/org/jetbrains/kotlin/backend/jvm => backend.common/src/org/jetbrains/kotlin/backend/common}/lower/SingleAbstractMethodLowering.kt (88%) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt similarity index 88% rename from compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt rename to compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt index e8917f699a3..bfc815e4ea3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/SingleAbstractMethodLowering.kt @@ -1,25 +1,19 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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.backend.jvm.lower +package org.jetbrains.kotlin.backend.common.lower +import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlock -import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase -import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin -import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound -import org.jetbrains.kotlin.codegen.SamWrapperCodegen.FUNCTION_FIELD_NAME -import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.* @@ -37,17 +31,10 @@ import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.isNullable import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions -internal val singleAbstractMethodPhase = makeIrFilePhase( - ::SingleAbstractMethodLowering, - name = "SingleAbstractMethod", - description = "Replace SAM conversions with instances of interface-implementing classes" -) - -class SingleAbstractMethodLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() { +abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() { // SAM wrappers are cached, either in the file class (if it exists), or in a top-level enclosing class. // In the latter case, the names of SAM wrappers depend on the order of classes in the file. For example: // @@ -75,6 +62,11 @@ class SingleAbstractMethodLowering(val context: JvmBackendContext) : FileLowerin private val inlineCachedImplementations = mutableMapOf() private var enclosingClass: IrClass? = null + open val privateGeneratedWrapperVisibility: Visibility + get() = Visibilities.PRIVATE + + abstract fun getSuperTypeForWrapper(typeOperand: IrType): IrType + override fun lower(irFile: IrFile) { enclosingClass = irFile.declarations.filterIsInstance().find { it.origin == IrDeclarationOrigin.FILE_CLASS } irFile.transformChildrenVoid() @@ -99,7 +91,7 @@ class SingleAbstractMethodLowering(val context: JvmBackendContext) : FileLowerin // TODO: there must be exactly one wrapper per Java interface; ideally, if the interface has generic // parameters, so should the wrapper. Currently, we just erase them and generate something that // erases to the same result at codegen time. - val erasedSuperType = expression.typeOperand.erasedUpperBound.defaultType + val erasedSuperType = getSuperTypeForWrapper(expression.typeOperand) val superType = if (expression.typeOperand.isNullable()) erasedSuperType.makeNullable() else erasedSuperType val invokable = expression.argument.transform(this, null) context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).apply { @@ -136,6 +128,9 @@ class SingleAbstractMethodLowering(val context: JvmBackendContext) : FileLowerin } } + private val SAM_WRAPPER_SUFFIX = "$0" + private val FUNCTION_FIELD_NAME = "function" + // Construct a class that wraps an invokable object into an implementation of an interface: // class sam$n(private val invokable: F) : Interface { override fun method(...) = invokable(...) } private fun createObjectProxy(superType: IrType, generatePublicWrapper: Boolean): IrClass { @@ -153,10 +148,10 @@ class SingleAbstractMethodLowering(val context: JvmBackendContext) : FileLowerin val wrappedFunctionClass = context.ir.symbols.functionN(superMethod.valueParameters.size).owner val wrappedFunctionType = wrappedFunctionClass.defaultType - val wrapperVisibility = if (generatePublicWrapper) Visibilities.PUBLIC else JavaVisibilities.PACKAGE_VISIBILITY + val wrapperVisibility = if (generatePublicWrapper) Visibilities.PUBLIC else privateGeneratedWrapperVisibility val subclass = buildClass { name = wrapperName - origin = JvmLoweredDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION + origin = IrDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION visibility = wrapperVisibility }.apply { createImplicitParameterDeclarationWithWrappedDescriptor() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index c71a511c3e4..57337b55a53 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -27,7 +27,6 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object SYNTHETIC_METHOD_FOR_TYPEALIAS_ANNOTATIONS : IrDeclarationOriginImpl("SYNTHETIC_METHOD_FOR_TYPEALIAS_ANNOTATIONS", isSynthetic = true) object GENERATED_PROPERTY_REFERENCE : IrDeclarationOriginImpl("GENERATED_PROPERTY_REFERENCE", isSynthetic = true) - object GENERATED_SAM_IMPLEMENTATION : IrDeclarationOriginImpl("GENERATED_SAM_IMPLEMENTATION", isSynthetic = true) object GENERATED_MEMBER_IN_CALLABLE_REFERENCE : IrDeclarationOriginImpl("GENERATED_MEMBER_IN_CALLABLE_REFERENCE", isSynthetic = false) object ENUM_MAPPINGS_FOR_WHEN : IrDeclarationOriginImpl("ENUM_MAPPINGS_FOR_WHEN", isSynthetic = true) object SYNTHETIC_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("SYNTHETIC_INLINE_CLASS_MEMBER", isSynthetic = true) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt new file mode 100644 index 00000000000..35885d963d6 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmSingleAbstractMethodLowering.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.lower.SingleAbstractMethodLowering +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.load.java.JavaVisibilities + +internal val singleAbstractMethodPhase = makeIrFilePhase( + ::JvmSingleAbstractMethodLowering, + name = "SingleAbstractMethod", + description = "Replace SAM conversions with instances of interface-implementing classes" +) + +private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : SingleAbstractMethodLowering(context) { + override val privateGeneratedWrapperVisibility: Visibility + get() = JavaVisibilities.PACKAGE_VISIBILITY + + override fun getSuperTypeForWrapper(typeOperand: IrType) = typeOperand.erasedUpperBound.defaultType +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index a0d1364d9e9..d30fe6b5b17 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -57,6 +57,8 @@ interface IrDeclarationOrigin { object ADAPTER_FOR_CALLABLE_REFERENCE : IrDeclarationOriginImpl("ADAPTER_FOR_CALLABLE_REFERENCE") object ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE : IrDeclarationOriginImpl("ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE") + object GENERATED_SAM_IMPLEMENTATION : IrDeclarationOriginImpl("GENERATED_SAM_IMPLEMENTATION", isSynthetic = true) + val isSynthetic: Boolean get() = false }