From cfd62c15bfcca83f6b0adb6de989d4cda3a19ce1 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 24 Sep 2020 16:49:36 +0300 Subject: [PATCH] JVM_IR KT-36994 don't generate stub if present in superclass --- .../jvm/lower/CollectionStubMethodLowering.kt | 37 +++++++++++------- .../extendingAbstractCollection.kt | 3 ++ .../extendingAbstractCollection.txt | 23 +++++++++++ .../extendingAbstractCollection_ir.txt | 22 +++++++++++ .../noStubsInJavaSuperClass.kt | 1 - .../noStubsInJavaSuperClass2.kt | 18 +++++++++ .../noStubsInJavaSuperClass2.txt | 39 +++++++++++++++++++ .../collectionStubs/stubsFromSuperclass.kt | 1 - .../codegen/BytecodeListingTestGenerated.java | 10 +++++ .../ir/IrBytecodeListingTestGenerated.java | 10 +++++ 10 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt create mode 100644 compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.txt create mode 100644 compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection_ir.txt create mode 100644 compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt create mode 100644 compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.txt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt index 16aa00c1449..0ff7cefeee2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CollectionStubMethodLowering.kt @@ -294,25 +294,32 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl // Compute stubs that should be generated, compare based on signature private fun generateRelevantStubMethods(irClass: IrClass): List { - val ourStubsForCollectionClasses = collectionStubComputer.stubsForCollectionClasses(irClass) - val superStubClasses = irClass.superClass?.superClassChain?.map { superClass -> - collectionStubComputer.stubsForCollectionClasses(superClass).map { it.readOnlyClass } - }?.fold(emptySet(), { a, b -> a union b }) ?: emptySet() - - // do a second filtering to ensure only most relevant classes are included. - val redundantClasses = ourStubsForCollectionClasses.filter { (readOnlyClass) -> - ourStubsForCollectionClasses.any { readOnlyClass != it.readOnlyClass && it.readOnlyClass.isSubtypeOfClass(readOnlyClass) } - }.map { it.readOnlyClass } - - // perform type substitution and type erasure here - return ourStubsForCollectionClasses.filter { (readOnlyClass) -> - readOnlyClass !in redundantClasses && readOnlyClass !in superStubClasses - }.flatMap { (readOnlyClass, mutableClass, mutableOnlyMethods) -> + fun createStubFuns(stubs: CollectionStubComputer.StubsForCollectionClass): List { + val (readOnlyClass, mutableClass, mutableOnlyMethods) = stubs val substitutionMap = computeSubstitutionMap(readOnlyClass.owner, mutableClass.owner, irClass) - mutableOnlyMethods.map { function -> + return mutableOnlyMethods.map { function -> createStubMethod(function, irClass, substitutionMap) } } + + val classStubs = collectionStubComputer.stubsForCollectionClasses(irClass) + + val superClassesStubs = irClass.superClass?.run { + superClassChain.flatMap { superClass -> + collectionStubComputer.stubsForCollectionClasses(superClass) + }.toList() + } ?: emptyList() + + val relevantStubs = + classStubs.filter { (readOnlyClass) -> + classStubs.none { readOnlyClass != it.readOnlyClass && it.readOnlyClass.isSubtypeOfClass(readOnlyClass) } && + superClassesStubs.none { it.readOnlyClass == readOnlyClass } + } + + val classStubFuns = relevantStubs.flatMap { createStubFuns(it) } + val superClassStubSignatures = superClassesStubs.flatMap { createStubFuns(it) }.mapTo(HashSet()) { it.toJvmSignature() } + + return classStubFuns.filter { it.toJvmSignature() !in superClassStubSignatures } } private fun Collection.findMostSpecificTypeForClass(classifier: IrClassSymbol): IrType { diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt new file mode 100644 index 00000000000..bce3019409a --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt @@ -0,0 +1,3 @@ +abstract class AC : Collection + +abstract class ASet : AC(), Set \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.txt new file mode 100644 index 00000000000..771efd033e6 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.txt @@ -0,0 +1,23 @@ +@kotlin.Metadata +public abstract class AC { + // source: 'extendingAbstractCollection.kt' + public method (): void + public method add(p0: java.lang.Object): boolean + public method addAll(p0: java.util.Collection): boolean + public method clear(): void + public abstract method contains(p0: java.lang.Object): boolean + public abstract method getSize(): int + public method iterator(): java.util.Iterator + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method retainAll(p0: java.util.Collection): boolean + public bridge final method size(): int + public method toArray(): java.lang.Object[] + public method toArray(p0: java.lang.Object[]): java.lang.Object[] +} + +@kotlin.Metadata +public abstract class ASet { + // source: 'extendingAbstractCollection.kt' + public method (): void +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection_ir.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection_ir.txt new file mode 100644 index 00000000000..bbbabe36b9c --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection_ir.txt @@ -0,0 +1,22 @@ +@kotlin.Metadata +public abstract class AC { + // source: 'extendingAbstractCollection.kt' + public method (): void + public method add(p0: java.lang.Object): boolean + public method addAll(p0: java.util.Collection): boolean + public method clear(): void + public abstract method getSize(): int + public method iterator(): java.util.Iterator + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method retainAll(p0: java.util.Collection): boolean + public bridge final method size(): int + public method toArray(): java.lang.Object[] + public method toArray(p0: java.lang.Object[]): java.lang.Object[] +} + +@kotlin.Metadata +public abstract class ASet { + // source: 'extendingAbstractCollection.kt' + public method (): void +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt index 354f7e5d8ac..401e304ccaa 100644 --- a/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME // FILE: test/B.java diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt new file mode 100644 index 00000000000..139d1119902 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt @@ -0,0 +1,18 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JVM +// ^ see KT-42179 + +// FILE: test/JC.java +package test; + +import java.util.Collection; + +public abstract class JC implements Collection { +} + +// FILE: noStubsInJavaSuperClass2.kt +package test + +abstract class KSet : JC(), Set + +abstract class KList : JC(), List \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.txt b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.txt new file mode 100644 index 00000000000..a1fabfb0f62 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.txt @@ -0,0 +1,39 @@ +@kotlin.Metadata +public abstract class test/KList { + // source: 'noStubsInJavaSuperClass2.kt' + public method (): void + public method add(p0: int, p1: java.lang.Object): void + public method add(p0: java.lang.Object): boolean + public method addAll(p0: int, p1: java.util.Collection): boolean + public method addAll(p0: java.util.Collection): boolean + public method clear(): void + public abstract method getSize(): int + public method listIterator(): java.util.ListIterator + public method listIterator(p0: int): java.util.ListIterator + public method remove(p0: int): java.lang.Object + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method retainAll(p0: java.util.Collection): boolean + public method set(p0: int, p1: java.lang.Object): java.lang.Object + public bridge final method size(): int + public method subList(p0: int, p1: int): java.util.List + public method toArray(): java.lang.Object[] + public method toArray(p0: java.lang.Object[]): java.lang.Object[] +} + +@kotlin.Metadata +public abstract class test/KSet { + // source: 'noStubsInJavaSuperClass2.kt' + public method (): void + public method add(p0: java.lang.Object): boolean + public method addAll(p0: java.util.Collection): boolean + public method clear(): void + public abstract method getSize(): int + public method iterator(): java.util.Iterator + public method remove(p0: java.lang.Object): boolean + public method removeAll(p0: java.util.Collection): boolean + public method retainAll(p0: java.util.Collection): boolean + public bridge final method size(): int + public method toArray(): java.lang.Object[] + public method toArray(p0: java.lang.Object[]): java.lang.Object[] +} diff --git a/compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt index bb9b84f058b..621e835c000 100644 --- a/compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt +++ b/compiler/testData/codegen/bytecodeListing/collectionStubs/stubsFromSuperclass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME open class A : Collection { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 835aee39eac..c9c370fa920 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -254,6 +254,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/emptyList.kt"); } + @TestMetadata("extendingAbstractCollection.kt") + public void testExtendingAbstractCollection() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt"); + } + @TestMetadata("noStubsForCollection.kt") public void testNoStubsForCollection() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsForCollection.kt"); @@ -284,6 +289,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt"); } + @TestMetadata("noStubsInJavaSuperClass2.kt") + public void testNoStubsInJavaSuperClass2() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt"); + } + @TestMetadata("noStubsInMutableIterable.kt") public void testNoStubsInMutableIterable() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInMutableIterable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 2dc8d12c218..6c23cef812d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -254,6 +254,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/emptyList.kt"); } + @TestMetadata("extendingAbstractCollection.kt") + public void testExtendingAbstractCollection() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/extendingAbstractCollection.kt"); + } + @TestMetadata("noStubsForCollection.kt") public void testNoStubsForCollection() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsForCollection.kt"); @@ -284,6 +289,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass.kt"); } + @TestMetadata("noStubsInJavaSuperClass2.kt") + public void testNoStubsInJavaSuperClass2() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInJavaSuperClass2.kt"); + } + @TestMetadata("noStubsInMutableIterable.kt") public void testNoStubsInMutableIterable() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/noStubsInMutableIterable.kt");