From 68f411395add0126f81c39347347462eda25562a Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 4 Mar 2016 16:45:52 +0300 Subject: [PATCH] Fix bridge generation for special builtin override Use method itself signature as common bridge delegate #KT-11285 Fixed --- .../kotlin/codegen/builtinSpecialBridges.kt | 24 ++++++++++++----- .../specialBuiltins/commonBridgesTarget.kt | 26 +++++++++++++++++++ .../bytecodeText/builtinFunctions/removeAt.kt | 12 ++++----- .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++++ 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt index df83251ebf9..bac74c3287f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/builtinSpecialBridges.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeAsSequence +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.singletonOrEmptyList import java.util.* @@ -75,10 +76,6 @@ object BuiltinSpecialBridgesUtil { val commonBridges = reachableDeclarations.mapTo(LinkedHashSet(), signatureByDescriptor) commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList()) - val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake) - if (superImplementationDescriptor != null || !fake || functionHandle.isAbstract) { - commonBridges.remove(methodItself) - } if (fake) { for (overridden in function.overriddenDescriptors.map { it.original }) { @@ -88,13 +85,28 @@ object BuiltinSpecialBridgesUtil { } } - val bridges: MutableSet> = - (commonBridges.map { BridgeForBuiltinSpecial(it, specialBridgeSignature) } + specialBridge.singletonOrEmptyList()).toMutableSet() + val bridges: MutableSet> = mutableSetOf() + // Can be null if special builtin is final (e.g. 'name' in Enum) + // because there should be no stubs for override in subclasses + val superImplementationDescriptor = findSuperImplementationForStubDelegation(function, fake) if (superImplementationDescriptor != null) { bridges.add(BridgeForBuiltinSpecial(methodItself, signatureByDescriptor(superImplementationDescriptor), isDelegateToSuper = true)) } + if (commonBridges.remove(methodItself)) { + if (superImplementationDescriptor == null && fake && !functionHandle.isAbstract && methodItself != specialBridgeSignature) { + // The only case when superImplementationDescriptor, but method is fake and not abstract is enum members + // They have superImplementationDescriptor null because they are final + + // generate non-synthetic bridge 'getOrdinal()' to 'ordinal()' (see test enumAsOrdinaled.kt) + bridges.add(BridgeForBuiltinSpecial(methodItself, specialBridgeSignature, isSpecial = false, isDelegateToSuper = false)) + } + } + + bridges.addAll(commonBridges.map { BridgeForBuiltinSpecial(it, methodItself) }) + bridges.addIfNotNull(specialBridge) + return bridges } diff --git a/compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt b/compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt new file mode 100644 index 00000000000..04994b149c7 --- /dev/null +++ b/compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt @@ -0,0 +1,26 @@ +import java.util.* + +open class Base() : HashSet() { + override fun remove(element: Target): Boolean { + return true + } +} + +class Derived : Base() { + // common "synthetic bridge override fun remove(element: DatabaseEntity): Boolean" should call + // `INVOKEVIRTUAL remove(Issue)` + // instead of `INVOKEVIRTUAL remove(OBJECT)` + override fun remove(element: Issue): Boolean { + return super.remove(element) + } +} + +open class DatabaseEntity +class Issue: DatabaseEntity() + +fun box(): String { + val sprintIssues = Derived() + if (!sprintIssues.remove(Issue())) return "Fail" + + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/builtinFunctions/removeAt.kt b/compiler/testData/codegen/bytecodeText/builtinFunctions/removeAt.kt index 9aad3d2d0d3..849e6cb2022 100644 --- a/compiler/testData/codegen/bytecodeText/builtinFunctions/removeAt.kt +++ b/compiler/testData/codegen/bytecodeText/builtinFunctions/removeAt.kt @@ -90,18 +90,18 @@ fun box( } /* -9 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) -> calls in bridges with signature `public final bridge remove\(I\)` -16 INVOKEVIRTUAL A[0-9]+\.remove \(I\) -> calls to A1-A9.removeAt + 7 calls from `public synthetic bridge remove\(I\)Ljava/lang/Object;` +16 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) -> calls in bridges with signature `public final bridge remove\(I\)` + 7 calls from `public synthetic bridge remove\(I\)Ljava/lang/Object;` +9 INVOKEVIRTUAL A[0-9]+\.remove \(I\) -> calls to A1-A9.removeAt 1 INVOKEINTERFACE A9\.remove \(I\) -> call A9.removeAt 1 INVOKEINTERFACE A9\.remove \(Ljava/lang/Object;\) -> call A9.remove -2 INVOKEVIRTUAL A10\.remove \(I\) -> one call in function and one from `public synthetic bridge remove(I)Ljava/lang/Object;` bridge in A10 +1 INVOKEVIRTUAL A10\.remove \(I\) -> one call in 'box' function */ -// 9 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) -// 16 INVOKEVIRTUAL A[0-9]+\.remove \(I\) +// 16 INVOKEVIRTUAL A[0-9]+.removeAt \(I\) +// 9 INVOKEVIRTUAL A[0-9]+\.remove \(I\) // 1 INVOKEINTERFACE A9\.remove \(I\) // 1 INVOKEINTERFACE A9\.remove \(Ljava/lang/Object;\) -// 2 INVOKEVIRTUAL A10\.remove \(I\) +// 1 INVOKEVIRTUAL A10\.remove \(I\) // 2 INVOKEINTERFACE java\/util\/List.remove \(I\) // 2 INVOKEINTERFACE java\/util\/List.remove \(Ljava/lang/Object;\) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 4d1fc5d6392..25bb00ca75f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7585,6 +7585,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("commonBridgesTarget.kt") + public void testCommonBridgesTarget() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/commonBridgesTarget.kt"); + doTest(fileName); + } + @TestMetadata("emptyList.kt") public void testEmptyList() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/specialBuiltins/emptyList.kt");