JVM_IR JavaSamConversionEqualsHashCode

This commit is contained in:
Dmitry Petrov
2022-03-02 16:15:17 +03:00
committed by Space
parent 870cdfd226
commit fdb01d96f0
15 changed files with 204 additions and 7 deletions
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmSymbols
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.backend.jvm.lower.indy.*
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -75,6 +76,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
private val shouldGenerateIndyLambdas =
context.state.lambdasScheme == JvmClosureGenerationScheme.INDY
private val isJavaSamConversionWithEqualsHashCode =
context.state.languageVersionSettings.supportsFeature(LanguageFeature.JavaSamConversionEqualsHashCode)
override fun visitBlock(expression: IrBlock): IrExpression {
if (!expression.origin.isLambda)
return super.visitBlock(expression)
@@ -444,7 +448,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
private fun canGenerateIndySamConversionOnFunctionalExpression(samSuperType: IrType, expression: IrExpression): Boolean {
val samClass = samSuperType.classOrNull
?: throw AssertionError("Class type expected: ${samSuperType.render()}")
if (!samClass.owner.isFromJava())
if (!samClass.owner.isFromJava() || isJavaSamConversionWithEqualsHashCode)
return false
if (expression is IrBlock && expression.origin == IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
return false
@@ -595,7 +599,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
private val isKotlinFunInterface = samInterface != null && !samInterface.isFromJava()
private val needToGenerateSamEqualsHashCodeMethods =
isKotlinFunInterface && (isAdaptedReference || !isLambda)
(isKotlinFunInterface || isJavaSamConversionWithEqualsHashCode) &&
(isAdaptedReference || !isLambda)
private val superType =
samSuperType
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
import org.jetbrains.kotlin.backend.jvm.ir.rawType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -34,6 +35,10 @@ internal val singleAbstractMethodPhase = makeIrFilePhase(
)
private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : SingleAbstractMethodLowering(context) {
private val isJavaSamConversionWithEqualsHashCode =
context.state.languageVersionSettings.supportsFeature(LanguageFeature.JavaSamConversionEqualsHashCode)
override val inInlineFunctionScope: Boolean
get() = allScopes.any { it.irElement.safeAs<IrDeclaration>()?.isInPublicInlineScope == true }
@@ -56,5 +61,6 @@ private class JvmSingleAbstractMethodLowering(context: JvmBackendContext) : Sing
private val IrType.isKotlinFunInterface: Boolean
get() = getClass()?.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
override val IrType.needEqualsHashCodeMethods get() = isKotlinFunInterface
override val IrType.needEqualsHashCodeMethods
get() = isKotlinFunInterface || isJavaSamConversionWithEqualsHashCode
}
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
@@ -80,6 +81,10 @@ internal class LambdaMetafactoryArgumentsBuilder(
private val context: JvmBackendContext,
private val crossinlineLambdas: Set<IrSimpleFunction>
) {
private val isJavaSamConversionWithEqualsHashCode =
context.state.languageVersionSettings.supportsFeature(LanguageFeature.JavaSamConversionEqualsHashCode)
/**
* @see java.lang.invoke.LambdaMetafactory
*/
@@ -99,12 +104,10 @@ internal class LambdaMetafactoryArgumentsBuilder(
// Can't use JDK LambdaMetafactory for function references by default (because of 'equals').
// TODO special mode that would generate indy everywhere?
if (!reference.origin.isLambda && !samClass.isFromJava()) {
if (!reference.origin.isLambda && (!samClass.isFromJava() || isJavaSamConversionWithEqualsHashCode)) {
semanticsHazard = true
}
// Don't use JDK LambdaMetafactory for serializable lambdas
// TODO implement support for serializable lambdas with LambdaMetafactory (requires additional code for deserialization)
if (samClass.isInheritedFromSerializable()) {
shouldBeSerializable = true
}
@@ -133,7 +136,7 @@ internal class LambdaMetafactoryArgumentsBuilder(
functionHazard = true
}
// Can't use invokedynamic if the referenced function has to be inlined for correct semantics
// Can't use invokedynamic if the referenced function has to be inlined for correct semantics.
// Also in some cases like `private inline fun` we'd need accessors, which `SyntheticAccessorLowering`
// won't generate under the assumption that the inline function will be inlined. Plus if the function
// is in a different module we should probably copy it anyway (and regenerate all objects in it).