JVM_IR KT-45920 don't add special bridge if it clashes with known method
This commit is contained in:
committed by
TeamCityServer
parent
92d200e093
commit
c2a5b0b6e2
+20
-11
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -246,6 +245,9 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
private fun createBridges(irClass: IrClass, irFunction: IrSimpleFunction) {
|
private fun createBridges(irClass: IrClass, irFunction: IrSimpleFunction) {
|
||||||
// Track final overrides and bridges to avoid clashes
|
// Track final overrides and bridges to avoid clashes
|
||||||
val blacklist = mutableSetOf<Method>()
|
val blacklist = mutableSetOf<Method>()
|
||||||
|
val existingMethodSignatures = irClass.functions
|
||||||
|
.filter { !it.isFakeOverride && it.name == irFunction.name }
|
||||||
|
.mapTo(HashSet()) { it.jvmMethod }
|
||||||
|
|
||||||
// Add the current method to the blacklist if it is concrete or final.
|
// Add the current method to the blacklist if it is concrete or final.
|
||||||
val targetMethod = (irFunction.resolveFakeOverride() ?: irFunction).jvmMethod
|
val targetMethod = (irFunction.resolveFakeOverride() ?: irFunction).jvmMethod
|
||||||
@@ -260,10 +262,14 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
// bridge methods in a superclass.
|
// bridge methods in a superclass.
|
||||||
blacklist += irFunction.overriddenFinalSpecialBridges()
|
blacklist += irFunction.overriddenFinalSpecialBridges()
|
||||||
|
|
||||||
// We only generate a special bridge method if it does not clash with a final method in a superclass or the current method
|
fun getSpecialBridgeTargetAddingExtraBridges(): IrSimpleFunction {
|
||||||
val specialBridgeTarget = if (
|
// We only generate a special bridge method if it does not clash with a final method in a superclass or the current method
|
||||||
specialBridge.signature !in blacklist && (!irFunction.isFakeOverride || irFunction.jvmMethod != specialBridge.signature)
|
if (specialBridge.signature in blacklist ||
|
||||||
) {
|
irFunction.isFakeOverride && irFunction.jvmMethod == specialBridge.signature
|
||||||
|
) {
|
||||||
|
return irFunction
|
||||||
|
}
|
||||||
|
|
||||||
// If irFunction is a fake override, we replace it with a stub and redirect all calls to irFunction with
|
// If irFunction is a fake override, we replace it with a stub and redirect all calls to irFunction with
|
||||||
// calls to the stub instead. Otherwise we'll end up calling the special method itself and get into an
|
// calls to the stub instead. Otherwise we'll end up calling the special method itself and get into an
|
||||||
// infinite loop.
|
// infinite loop.
|
||||||
@@ -306,12 +312,16 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
blacklist += bridgeTarget.jvmMethod
|
blacklist += bridgeTarget.jvmMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (specialBridge.signature in existingMethodSignatures) {
|
||||||
|
return irFunction
|
||||||
|
}
|
||||||
|
|
||||||
blacklist += specialBridge.signature
|
blacklist += specialBridge.signature
|
||||||
irClass.addSpecialBridge(specialBridge, bridgeTarget)
|
return irClass.addSpecialBridge(specialBridge, bridgeTarget)
|
||||||
} else {
|
|
||||||
irFunction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val specialBridgeTarget = getSpecialBridgeTargetAddingExtraBridges()
|
||||||
|
|
||||||
// Deal with existing function that override special bridge methods.
|
// Deal with existing function that override special bridge methods.
|
||||||
if (!irFunction.isFakeOverride && specialBridge.methodInfo != null) {
|
if (!irFunction.isFakeOverride && specialBridge.methodInfo != null) {
|
||||||
irFunction.rewriteSpecialMethodBody(targetMethod, specialBridge.signature, specialBridge.methodInfo)
|
irFunction.rewriteSpecialMethodBody(targetMethod, specialBridge.signature, specialBridge.methodInfo)
|
||||||
@@ -434,9 +444,8 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
// This is technically wrong, but it's necessary to generate a method which maps to the same signature.
|
// This is technically wrong, but it's necessary to generate a method which maps to the same signature.
|
||||||
// In case of 'fun foo(): T', where 'T' is a type parameter with primitive upper bound (e.g., 'T : Char'),
|
// In case of 'fun foo(): T', where 'T' is a type parameter with primitive upper bound (e.g., 'T : Char'),
|
||||||
// 'foo' is mapped to 'foo()C', regardless of its overrides.
|
// 'foo' is mapped to 'foo()C', regardless of its overrides.
|
||||||
val inheritedOverrides = bridge.overriddenSymbols.flatMapTo(mutableSetOf()) { function ->
|
val inheritedOverrides = bridge.overriddenSymbols
|
||||||
function.owner.safeAs<IrSimpleFunction>()?.overriddenSymbols ?: emptyList()
|
.flatMapTo(mutableSetOf()) { it.owner.overriddenSymbols }
|
||||||
}
|
|
||||||
val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) {
|
val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) {
|
||||||
it.owner.allOverridden().map { override -> override.symbol }
|
it.owner.allOverridden().map { override -> override.symbol }
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
abstract class MindMap : MutableMap<Int, String> {
|
||||||
|
operator fun get(key: Any?): String? = null
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public abstract class MindMap {
|
||||||
|
// source: 'abstractMapRedefiningGetAny.kt'
|
||||||
|
public method <init>(): void
|
||||||
|
public abstract method containsKey(p0: int): boolean
|
||||||
|
public bridge final method containsKey(p0: java.lang.Object): boolean
|
||||||
|
public bridge final method containsValue(p0: java.lang.Object): boolean
|
||||||
|
public abstract method containsValue(p0: java.lang.String): boolean
|
||||||
|
public bridge final method entrySet(): java.util.Set
|
||||||
|
public final @org.jetbrains.annotations.Nullable method get(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.String
|
||||||
|
public abstract method get(p0: int): java.lang.String
|
||||||
|
public bridge final method get(p0: java.lang.Object): java.lang.Object
|
||||||
|
public abstract method getEntries(): java.util.Set
|
||||||
|
public abstract method getKeys(): java.util.Set
|
||||||
|
public abstract method getSize(): int
|
||||||
|
public abstract method getValues(): java.util.Collection
|
||||||
|
public bridge final method keySet(): java.util.Set
|
||||||
|
public abstract method remove(p0: int): java.lang.String
|
||||||
|
public bridge final method remove(p0: java.lang.Object): java.lang.Object
|
||||||
|
public bridge final method size(): int
|
||||||
|
public bridge final method values(): java.util.Collection
|
||||||
|
}
|
||||||
Vendored
+23
@@ -0,0 +1,23 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public abstract class MindMap {
|
||||||
|
// source: 'abstractMapRedefiningGetAny.kt'
|
||||||
|
public method <init>(): void
|
||||||
|
public abstract method containsKey(p0: int): boolean
|
||||||
|
public bridge final method containsKey(p0: java.lang.Object): boolean
|
||||||
|
public bridge final method containsValue(p0: java.lang.Object): boolean
|
||||||
|
public abstract method containsValue(p0: java.lang.String): boolean
|
||||||
|
public bridge final method entrySet(): java.util.Set
|
||||||
|
public final @org.jetbrains.annotations.Nullable method get(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.String
|
||||||
|
public abstract method get(p0: int): java.lang.String
|
||||||
|
public synthetic bridge method get(p0: java.lang.Object): java.lang.Object
|
||||||
|
public abstract method getEntries(): java.util.Set
|
||||||
|
public abstract method getKeys(): java.util.Set
|
||||||
|
public abstract method getSize(): int
|
||||||
|
public abstract method getValues(): java.util.Collection
|
||||||
|
public bridge final method keySet(): java.util.Set
|
||||||
|
public abstract method remove(p0: int): java.lang.String
|
||||||
|
public synthetic bridge method remove(p0: java.lang.Object): java.lang.Object
|
||||||
|
public bridge final method remove(p0: java.lang.Object): java.lang.String
|
||||||
|
public bridge final method size(): int
|
||||||
|
public bridge final method values(): java.util.Collection
|
||||||
|
}
|
||||||
+5
@@ -351,6 +351,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("abstractMapRedefiningGetAny.kt")
|
||||||
|
public void testAbstractMapRedefiningGetAny() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractMapRedefiningGetAny.kt");
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -351,6 +351,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
|||||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("abstractMapRedefiningGetAny.kt")
|
||||||
|
public void testAbstractMapRedefiningGetAny() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractMapRedefiningGetAny.kt");
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/collectionStubs"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user