From dd7d5dfdb3aaf07a96be67e05c5ffa83bde42a34 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Fri, 14 Feb 2020 17:11:07 +0300 Subject: [PATCH] JVM_IR: try to avoid resolveFakeOverride() in BridgeLowering One of the uses can be avoided, the other remains. Special overrides are now generated for MutableMap.remove and getOrDefault when there is an intermediate Java class, same as in old backend. --- .../backend/jvm/lower/BridgeLowering.kt | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 7064d35791e..7b1f7429b3a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -165,15 +165,10 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, if (irFunction.isJvmAbstract) return !irFunction.parentAsClass.isJvmInterface - // Finally, the JVM backend also ignores concrete fake overrides which are implemented in interfaces. + // Finally, the JVM backend also ignores concrete fake overrides whose implementation is directly inherited from an interface. // This is sound, since we do not generate type-specialized versions of fake overrides and if the method // were to override several interface methods the frontend would require a separate implementation. - // - // In addition, there are @PlatformDependent methods which only exist on newer JDK versions - // (MutableMap.remove and getOrDefault). Trying to produce (special) bridges for these methods could - // result in incorrect bytecode on older JVM versions. However, all such methods are declared - // in interfaces and thus we don't need a separate check for them. - return !irFunction.isFakeOverride || !irFunction.resolveFakeOverride()!!.parentAsClass.isJvmInterface + return !irFunction.isFakeOverride || irFunction.resolvesToClass() }) for (member in potentialBridgeTargets) { @@ -226,12 +221,15 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, irClass.addAbstractMethodStub(irFunction, specialBridge.methodInfo?.needsArgumentBoxing == true) } irFunction.modality != Modality.FINAL -> { - val superTarget = irFunction.overriddenSymbols.first { !it.owner.parentAsClass.isInterface }.owner + val overriddenFromClass = irFunction.overriddenFromClass()!! val superBridge = SpecialBridge( - irFunction, irFunction.jvmMethod, superQualifierSymbol = superTarget.parentAsClass.symbol, + irFunction, irFunction.jvmMethod, superQualifierSymbol = overriddenFromClass.parentAsClass.symbol, methodInfo = specialBridge.methodInfo?.copy(argumentsToCheck = 0), // For potential argument boxing isFinal = false, ) + // The part after ?: is needed for methods with default implementations in collection interfaces: + // MutableMap.remove() and getOrDefault(). + val superTarget = overriddenFromClass.takeIf { !it.isFakeOverride } ?: specialBridge.overridden irClass.declarations.remove(irFunction) irClass.addSpecialBridge(superBridge, superTarget) } @@ -486,3 +484,12 @@ private class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, } private fun IrDeclaration.comesFromJava() = parentAsClass.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB + +// Check whether a fake override will resolve to an implementation in class, not an interface. +private fun IrSimpleFunction.resolvesToClass(): Boolean { + val overriddenFromClass = overriddenFromClass() ?: return false + return overriddenFromClass.modality != Modality.ABSTRACT +} + +private fun IrSimpleFunction.overriddenFromClass(): IrSimpleFunction? = + overriddenSymbols.singleOrNull { !it.owner.parentAsClass.isJvmInterface }?.owner