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.name.Name
|
||||
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.commons.Method
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -246,6 +245,9 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
private fun createBridges(irClass: IrClass, irFunction: IrSimpleFunction) {
|
||||
// Track final overrides and bridges to avoid clashes
|
||||
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.
|
||||
val targetMethod = (irFunction.resolveFakeOverride() ?: irFunction).jvmMethod
|
||||
@@ -260,10 +262,14 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
// bridge methods in a superclass.
|
||||
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
|
||||
val specialBridgeTarget = if (
|
||||
specialBridge.signature !in blacklist && (!irFunction.isFakeOverride || irFunction.jvmMethod != specialBridge.signature)
|
||||
) {
|
||||
fun getSpecialBridgeTargetAddingExtraBridges(): IrSimpleFunction {
|
||||
// We only generate a special bridge method if it does not clash with a final method in a superclass or the current method
|
||||
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
|
||||
// calls to the stub instead. Otherwise we'll end up calling the special method itself and get into an
|
||||
// infinite loop.
|
||||
@@ -306,12 +312,16 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
blacklist += bridgeTarget.jvmMethod
|
||||
}
|
||||
|
||||
if (specialBridge.signature in existingMethodSignatures) {
|
||||
return irFunction
|
||||
}
|
||||
|
||||
blacklist += specialBridge.signature
|
||||
irClass.addSpecialBridge(specialBridge, bridgeTarget)
|
||||
} else {
|
||||
irFunction
|
||||
return irClass.addSpecialBridge(specialBridge, bridgeTarget)
|
||||
}
|
||||
|
||||
val specialBridgeTarget = getSpecialBridgeTargetAddingExtraBridges()
|
||||
|
||||
// Deal with existing function that override special bridge methods.
|
||||
if (!irFunction.isFakeOverride && specialBridge.methodInfo != null) {
|
||||
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.
|
||||
// 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.
|
||||
val inheritedOverrides = bridge.overriddenSymbols.flatMapTo(mutableSetOf()) { function ->
|
||||
function.owner.safeAs<IrSimpleFunction>()?.overriddenSymbols ?: emptyList()
|
||||
}
|
||||
val inheritedOverrides = bridge.overriddenSymbols
|
||||
.flatMapTo(mutableSetOf()) { it.owner.overriddenSymbols }
|
||||
val redundantOverrides = inheritedOverrides.flatMapTo(mutableSetOf()) {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("abstractMapRedefiningGetAny.kt")
|
||||
public void testAbstractMapRedefiningGetAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractMapRedefiningGetAny.kt");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("abstractMapRedefiningGetAny.kt")
|
||||
public void testAbstractMapRedefiningGetAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/collectionStubs/abstractMapRedefiningGetAny.kt");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCollectionStubs() throws Exception {
|
||||
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