JVM IR: Mangle overridden symbols in non-inline functions (KT-52394)

This commit is contained in:
Steven Schäfer
2022-05-16 16:46:29 +02:00
committed by teamcity
parent 0fc676a20c
commit 90d09dce2c
10 changed files with 87 additions and 18 deletions
@@ -21475,6 +21475,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/kt51672.kt");
}
@Test
@TestMetadata("kt52394.kt")
public void testKt52394() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt52394.kt");
}
@Test
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
@@ -343,14 +343,12 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
for (override in irFunction.allOverridden()) {
if (override.isFakeOverride) continue
val target = override.mangleFunctionIfNeeded()
val signature = target.jvmMethod
val signature = override.jvmMethod
if (targetMethod != signature && signature !in blacklist) {
val bridge = generated.getOrPut(signature) {
Bridge(target, signature)
Bridge(override, signature)
}
bridge.overriddenSymbols += target.symbol
bridge.overriddenSymbols += override.symbol
}
}
@@ -362,16 +360,6 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
.forEach { irClass.addBridge(it, bridgeTarget) }
}
private fun IrSimpleFunction.mangleFunctionIfNeeded(): IrSimpleFunction {
if (!hasMangledReturnType && !hasMangledParameters) return this
val replacement = context.inlineClassReplacements.getReplacementFunction(this) ?: return this
if (name.asString().substringAfterLast('-') == replacement.name.asString().substringAfterLast('-')) {
// function is already mangled
return this
}
return replacement
}
private fun IrSimpleFunction.isClashingWithPotentialBridge(name: Name, signature: Method): Boolean =
(!this.isFakeOverride || this.modality == Modality.FINAL) && this.name == name && this.jvmMethod == signature
@@ -81,6 +81,16 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
val replacement = replacements.getReplacementFunction(function)
if (replacement == null) {
function.transformChildrenVoid()
// Non-mangled functions can override mangled functions under some conditions, e.g., a function
// `fun f(): Nothing` can override a function `fun f(): UInt`. The former is not mangled, while
// the latter is.
//
// This is a potential problem for bridge generation, where we have to ensure that the overridden
// symbols are always up to date. Right now they might not be since we lower each file independently
// and since deserialized declarations are not mangled at all.
if (function is IrSimpleFunction) {
function.overriddenSymbols = replacements.replaceOverriddenSymbols(function)
}
return null
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.isInt
@@ -304,11 +305,21 @@ class MemoizedInlineClassReplacements(
}
}
overriddenSymbols = function.overriddenSymbols.map {
getReplacementFunction(it.owner)?.symbol ?: it
}
overriddenSymbols = replaceOverriddenSymbols(function)
}
body()
}
override val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol> =
storageManager.createMemoizedFunction { irSimpleFunction ->
irSimpleFunction.overriddenSymbols.map {
computeOverrideReplacement(it.owner).symbol
}
}
private fun computeOverrideReplacement(function: IrSimpleFunction): IrSimpleFunction =
getReplacementFunction(function) ?: function.also {
function.overriddenSymbols = replaceOverriddenSymbols(function)
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import java.util.concurrent.ConcurrentHashMap
@@ -29,4 +30,8 @@ class MemoizedMultiFieldValueClassReplacements(
override val getReplacementFunction: (IrFunction) -> IrSimpleFunction? = storageManager.createMemoizedFunctionWithNullableValues {
TODO()
}
override val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol> = storageManager.createMemoizedFunction {
TODO()
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: IrFactory, protected val context: JvmBackendContext) {
/**
@@ -17,4 +18,5 @@ abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: I
abstract val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction>
abstract val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol>
}
+30
View File
@@ -0,0 +1,30 @@
// WITH_REFLECT
// TARGET_BACKEND: JVM
import kotlin.reflect.full.declaredFunctions
annotation class Anno(val value: String)
@JvmInline
value class A(val value: String)
abstract class B {
@Anno(value = "K")
abstract fun f(): A?
}
class C : B() {
override fun f(): A? = A("O")
}
class D : B() {
override fun f(): Nothing? = null
}
fun box(): String {
val o = if ((D() as B).f() == null) (C() as B).f()!!.value else "Fail"
val annotations = B::class.declaredFunctions.single().annotations
val k = (annotations.single() as Anno).value
return o + k
}
@@ -21001,6 +21001,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt51672.kt");
}
@Test
@TestMetadata("kt52394.kt")
public void testKt52394() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt52394.kt");
}
@Test
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
@@ -21475,6 +21475,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/kt51672.kt");
}
@Test
@TestMetadata("kt52394.kt")
public void testKt52394() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt52394.kt");
}
@Test
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
@@ -17534,6 +17534,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/kt51672.kt");
}
@TestMetadata("kt52394.kt")
public void testKt52394() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt52394.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());