JVM_IR: do not move receivers on functions with inline class parameters

^KT-48993 Fixed
This commit is contained in:
pyos
2021-10-05 10:41:09 +02:00
committed by Ilmir Usmanov
parent 3eb3015688
commit 337cbeded1
7 changed files with 64 additions and 34 deletions
@@ -19488,6 +19488,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
} }
@Test
@TestMetadata("kt48993.kt")
public void testKt48993() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
}
@Test @Test
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod
import org.jetbrains.kotlin.backend.jvm.codegen.extensionReceiverName
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId import org.jetbrains.kotlin.backend.jvm.codegen.parentClassId
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
@@ -81,10 +82,7 @@ class MemoizedInlineClassReplacements(
// Otherwise, mangle functions with mangled parameters, ignoring constructors // Otherwise, mangle functions with mangled parameters, ignoring constructors
it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) -> it is IrSimpleFunction && !it.isFromJava() && (it.hasMangledParameters || mangleReturnTypes && it.hasMangledReturnType) ->
if (it.dispatchReceiverParameter != null) createMethodReplacement(it)
createMethodReplacement(it)
else
createStaticReplacement(it)
else -> else ->
null null
@@ -182,9 +180,11 @@ class MemoizedInlineClassReplacements(
private fun createMethodReplacement(function: IrFunction): IrSimpleFunction = private fun createMethodReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, function.origin) { buildReplacement(function, function.origin) {
originalFunctionForMethodReplacement[this] = function originalFunctionForMethodReplacement[this] = function
require(function.dispatchReceiverParameter != null && function is IrSimpleFunction)
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1) dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this, index = -1, name = Name.identifier("\$receiver")) extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(
// The function's name will be mangled, so preserve the old receiver name.
this, index = -1, name = Name.identifier(function.extensionReceiverName(context.state))
)
valueParameters = function.valueParameters.mapIndexed { index, parameter -> valueParameters = function.valueParameters.mapIndexed { index, parameter ->
parameter.copyTo(this, index = index, defaultValue = null).also { parameter.copyTo(this, index = index, defaultValue = null).also {
// Assuming that constructors and non-override functions are always replaced with the unboxed // Assuming that constructors and non-override functions are always replaced with the unboxed
@@ -207,11 +207,8 @@ class MemoizedInlineClassReplacements(
) )
} }
function.extensionReceiverParameter?.let { function.extensionReceiverParameter?.let {
val baseName =
(function as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name?.asStringStripSpecialMarkers()
?: function.name
newValueParameters += it.copyTo( newValueParameters += it.copyTo(
this, index = newValueParameters.size, name = Name.identifier("\$this\$$baseName"), this, index = newValueParameters.size, name = Name.identifier(function.extensionReceiverName(context.state)),
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER
) )
} }
@@ -69,7 +69,7 @@ class FunctionCodegen(private val irFunction: IrFunction, private val classCodeg
val methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode) val methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode)
if (context.state.generateParametersMetadata && !isSynthetic) { if (context.state.generateParametersMetadata && !isSynthetic) {
generateParameterNames(irFunction, methodVisitor, signature, context.state) generateParameterNames(irFunction, methodVisitor, context.state)
} }
if (irFunction.origin !in methodOriginsWithoutAnnotations) { if (irFunction.origin !in methodOriginsWithoutAnnotations) {
@@ -329,23 +329,16 @@ private fun IrValueParameter.isSyntheticMarkerParameter(): Boolean =
origin == IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER || origin == IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER ||
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_MARKER_PARAMETER origin == JvmLoweredDeclarationOrigin.SYNTHETIC_MARKER_PARAMETER
private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jvmSignature: JvmMethodSignature, state: GenerationState) { private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, state: GenerationState) {
val iterator = irFunction.valueParameters.iterator() irFunction.extensionReceiverParameter?.let {
for (parameterSignature in jvmSignature.valueParameters) { mv.visitParameter(irFunction.extensionReceiverName(state), Opcodes.ACC_MANDATED)
val irParameter = when (parameterSignature.kind) { }
JvmMethodParameterKind.RECEIVER -> irFunction.extensionReceiverParameter!! for (irParameter in irFunction.valueParameters) {
else -> iterator.next()
}
val name = when (parameterSignature.kind) {
JvmMethodParameterKind.RECEIVER -> getNameForReceiverParameter(irFunction, state)
else -> irParameter.name.asString()
}
// A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared // A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared
// explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9). // explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).
// A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter // A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter
// declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1). // declared implicitly in source code (§8.8.1, §8.8.9, §8.9.3, §15.9.5.1).
val access = when { val access = when {
irParameter == irFunction.extensionReceiverParameter -> Opcodes.ACC_MANDATED
irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED irParameter.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS -> Opcodes.ACC_MANDATED
// TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected // TODO mark these backend-common origins as synthetic? (note: ExpressionCodegen is still expected
// to generate LVT entries for them) // to generate LVT entries for them)
@@ -356,24 +349,21 @@ private fun generateParameterNames(irFunction: IrFunction, mv: MethodVisitor, jv
irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC irParameter.origin.isSynthetic -> Opcodes.ACC_SYNTHETIC
else -> 0 else -> 0
} }
mv.visitParameter(name, access) mv.visitParameter(irParameter.name.asString(), access)
} }
} }
private fun getNameForReceiverParameter(irFunction: IrFunction, state: GenerationState): String { internal fun IrFunction.extensionReceiverName(state: GenerationState): String {
if (!state.languageVersionSettings.supportsFeature(LanguageFeature.NewCapturedReceiverFieldNamingConvention)) { if (!state.languageVersionSettings.supportsFeature(LanguageFeature.NewCapturedReceiverFieldNamingConvention)) {
return AsmUtil.RECEIVER_PARAMETER_NAME return AsmUtil.RECEIVER_PARAMETER_NAME
} }
// Current codegen never touches CALL_LABEL_FOR_LAMBDA_ARGUMENT extensionReceiverParameter?.let {
// if (irFunction is IrSimpleFunction) { if (it.name.asString().startsWith(AsmUtil.LABELED_THIS_PARAMETER)) {
// val labelName = bindingContext.get(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, irFunction.descriptor) return it.name.asString()
// if (labelName != null) { }
// return getLabeledThisName(labelName, prefix, defaultName) }
// } val callableName = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name ?: name
// }
val callableName = irFunction.safeAs<IrSimpleFunction>()?.correspondingPropertySymbol?.owner?.name ?: irFunction.name
return if (callableName.isSpecial || !Name.isValidIdentifier(callableName.asString())) return if (callableName.isSpecial || !Name.isValidIdentifier(callableName.asString()))
AsmUtil.RECEIVER_PARAMETER_NAME AsmUtil.RECEIVER_PARAMETER_NAME
else else
+20
View File
@@ -0,0 +1,20 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: 1.kt
inline class C(val x: String)
// FILE: 2.kt
@file:JvmMultifileClass
@file:JvmName("Multifile")
private var result: String? = null
var String.k: C
get() = C(this + result!!)
set(value) { result = value.x }
// FILE: 3.kt
fun box(): String {
"".k = C("K")
return "O".k.x
}
@@ -19356,6 +19356,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
} }
@Test
@TestMetadata("kt48993.kt")
public void testKt48993() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
}
@Test @Test
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
@@ -19488,6 +19488,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
} }
@Test
@TestMetadata("kt48993.kt")
public void testKt48993() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
}
@Test @Test
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
@@ -16078,6 +16078,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt47762.kt");
} }
@TestMetadata("kt48993.kt")
public void testKt48993() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt48993.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");