JVM IR: Mangle interface implementation methods in inline classes
This commit is contained in:
committed by
Alexander Udalov
parent
d21be3b665
commit
6a1e35389c
+17
-12
@@ -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.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
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.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.config.ApiVersion
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
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)
|
if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null)
|
||||||
return listOf(replacement)
|
return listOf(replacement)
|
||||||
|
|
||||||
// Update the overridden symbols to point to their inline class replacements
|
// If the original function has value parameters which need mangling we still need to replace
|
||||||
function.overriddenSymbols = replacement.overriddenSymbols
|
// it with a mangled version.
|
||||||
|
val bridgeFunction = if (!function.isFakeOverride && function.fullValueParameterList.any { it.type.requiresMangling }) {
|
||||||
// Replace the function body with a wrapper
|
context.inlineClassReplacements.createMethodReplacement(function)
|
||||||
if (!function.isFakeOverride || !function.parentAsClass.isInline) {
|
|
||||||
createBridgeBody(function, replacement)
|
|
||||||
} else {
|
} else {
|
||||||
// Fake overrides redirect from the replacement to the original function, which is in turn replaced during interfacePhase.
|
// Update the overridden symbols to point to their inline class replacements
|
||||||
createBridgeBody(replacement, function)
|
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
|
// Secondary constructors for boxed types get translated to static functions returning
|
||||||
|
|||||||
+2
-2
@@ -97,13 +97,13 @@ object InlineClassAbi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val IrType.requiresMangling: Boolean
|
internal val IrType.requiresMangling: Boolean
|
||||||
get() {
|
get() {
|
||||||
val irClass = erasedUpperBound
|
val irClass = erasedUpperBound
|
||||||
return irClass.isInline && irClass.fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME
|
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
|
get() = listOfNotNull(extensionReceiverParameter) + valueParameters
|
||||||
|
|
||||||
internal val IrFunction.hasMangledParameters: Boolean
|
internal val IrFunction.hasMangledParameters: Boolean
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ class MemoizedInlineClassReplacements {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
internal fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
|
||||||
buildReplacement(function, function.origin) {
|
buildReplacement(function, function.origin) {
|
||||||
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
|
||||||
val newValueParameters = ArrayList<IrValueParameter>()
|
val newValueParameters = ArrayList<IrValueParameter>()
|
||||||
|
|||||||
Vendored
+18
@@ -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");
|
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")
|
@TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt")
|
||||||
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
|
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");
|
||||||
|
|||||||
+5
@@ -2855,6 +2855,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt");
|
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")
|
@TestMetadata("noActualCallsOfInlineFunctionsOfInlineClass.kt")
|
||||||
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
|
public void testNoActualCallsOfInlineFunctionsOfInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");
|
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/noActualCallsOfInlineFunctionsOfInlineClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user