JVM IR: Mangle interface implementation methods in inline classes

This commit is contained in:
Steven Schäfer
2020-03-11 11:50:34 +01:00
committed by Alexander Udalov
parent d21be3b665
commit 6a1e35389c
6 changed files with 48 additions and 15 deletions
@@ -14,10 +14,8 @@ import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.*
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.inlineClassFieldName
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineClassFieldGetter
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isPrimaryInlineClassConstructor
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
@@ -136,18 +134,25 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null)
return listOf(replacement)
// Update the overridden symbols to point to their inline class replacements
function.overriddenSymbols = replacement.overriddenSymbols
// Replace the function body with a wrapper
if (!function.isFakeOverride || !function.parentAsClass.isInline) {
createBridgeBody(function, replacement)
// If the original function has value parameters which need mangling we still need to replace
// it with a mangled version.
val bridgeFunction = if (!function.isFakeOverride && function.fullValueParameterList.any { it.type.requiresMangling }) {
context.inlineClassReplacements.createMethodReplacement(function)
} else {
// Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase.
createBridgeBody(replacement, function)
// Update the overridden symbols to point to their inline class replacements
function.overriddenSymbols = replacement.overriddenSymbols
function
}
return listOf(replacement, function)
// Replace the function body with a wrapper
if (!bridgeFunction.isFakeOverride || !bridgeFunction.parentAsClass.isInline) {
createBridgeBody(bridgeFunction, replacement)
} else {
// Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase.
createBridgeBody(replacement, bridgeFunction)
}
return listOf(replacement, bridgeFunction)
}
// Secondary constructors for boxed types get translated to static functions returning
@@ -97,13 +97,13 @@ object InlineClassAbi {
}
}
private val IrType.requiresMangling: Boolean
internal val IrType.requiresMangling: Boolean
get() {
val irClass = erasedUpperBound
return irClass.isInline && irClass.fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME
}
private val IrFunction.fullValueParameterList: List<IrValueParameter>
internal val IrFunction.fullValueParameterList: List<IrValueParameter>
get() = listOfNotNull(extensionReceiverParameter) + valueParameters
internal val IrFunction.hasMangledParameters: Boolean
@@ -124,7 +124,7 @@ class MemoizedInlineClassReplacements {
}
}
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
internal fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, function.origin) {
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
val newValueParameters = ArrayList<IrValueParameter>()
@@ -0,0 +1,18 @@
// !LANGUAGE: +InlineClasses
interface A<T> {
fun foo(a: T): String
}
inline class Foo(val x: Long) : A<Foo> {
override fun foo(a: Foo): String = if (x != a.x) "OK" else "FAIL"
}
fun box(): String {
return Foo(0L).foo(Foo(1L))
}
// 1 public foo-GWb7d6U\(J\)Ljava/lang/String;
// 1 public synthetic bridge foo\(Ljava/lang/Object;\)Ljava/lang/String;
// 1 public static foo-GWb7d6U\(JJ\)Ljava/lang/String;
// 0 foo\(J
@@ -2810,6 +2810,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
}
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
public void testMangledInlineClassInterfaceImplementation() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt");
}
@TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt")
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");
@@ -2855,6 +2855,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
}
@TestMetadata("mangledInlineClassInterfaceImplementation.kt")
public void testMangledInlineClassInterfaceImplementation() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/mangledInlineClassInterfaceImplementation.kt");
}
@TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt")
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");