From 66cbe3b1a8e1d73e82ddbfc096191839b551758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Thu, 21 Nov 2019 11:00:44 +0100 Subject: [PATCH] JVM IR: Remove IrReplacementFunction --- .../jvm/lower/JvmInlineClassLowering.kt | 78 +++++++++---------- .../lower/JvmStringConcatenationLowering.kt | 2 +- .../MemoizedInlineClassReplacements.kt | 68 +++++----------- .../overridingMethodInGenericClass2.kt | 3 +- 4 files changed, 60 insertions(+), 91 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt index 62e4f27df48..8f14317939e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt @@ -14,7 +14,10 @@ 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 @@ -55,6 +58,12 @@ val jvmInlineClassPhase = makeIrFilePhase( private class JvmInlineClassLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() { private val valueMap = mutableMapOf() + private fun addBindingsFor(original: IrFunction, replacement: IrFunction) { + for ((param, newParam) in original.explicitParameters.zip(replacement.explicitParameters)) { + valueMap[param.symbol] = newParam + } + } + override fun lower(irFile: IrFile) { irFile.transformChildrenVoid() } @@ -62,9 +71,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F override fun visitClassNew(declaration: IrClass): IrStatement { // The arguments to the primary constructor are in scope in the initializers of IrFields. declaration.primaryConstructor?.let { - context.inlineClassReplacements.getReplacementFunction(it)?.let { replacement -> - valueMap.putAll(replacement.valueParameterMap) - } + context.inlineClassReplacements.getReplacementFunction(it)?.let { replacement -> addBindingsFor(it, replacement) } } declaration.transformDeclarationsFlat { memberDeclaration -> @@ -101,6 +108,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F return null } + addBindingsFor(function, replacement) return when (function) { is IrSimpleFunction -> transformSimpleFunctionFlat(function, replacement) is IrConstructor -> transformConstructorFlat(function, replacement) @@ -108,23 +116,20 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F } } - private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrReplacementFunction): List { - val worker = replacement.function - valueMap.putAll(replacement.valueParameterMap) - worker.valueParameters.forEach { it.transformChildrenVoid() } - worker.body = function.body?.transform(this, null)?.patchDeclarationParents(worker) - (worker as? IrAttributeContainer)?.copyAttributes(function) + private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List { + replacement.valueParameters.forEach { it.transformChildrenVoid() } + replacement.body = function.body?.transform(this, null)?.patchDeclarationParents(replacement) + (replacement as? IrAttributeContainer)?.copyAttributes(function) // Don't create a wrapper for functions which are only used in an unboxed context - if (function.overriddenSymbols.isEmpty() || worker.dispatchReceiverParameter != null) - return listOf(worker) + if (function.overriddenSymbols.isEmpty() || replacement.dispatchReceiverParameter != null) + return listOf(replacement) // Replace the function body with a wrapper context.createIrBuilder(function.symbol, function.startOffset, function.endOffset).run { - val call = irCall(worker).apply { + val call = irCall(replacement).apply { passTypeArgumentsFrom(function) - for (parameter in function.explicitParameters) { - val newParameter = replacement.valueParameterMap[parameter.symbol] ?: continue + for ((parameter, newParameter) in function.explicitParameters.zip(replacement.explicitParameters)) { putArgument(newParameter, irGet(parameter)) } } @@ -132,19 +137,18 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F function.body = irExprBody(call) } - return listOf(worker, function) + return listOf(replacement, function) } // Secondary constructors for boxed types get translated to static functions returning // unboxed arguments. We remove the original constructor. - private fun transformConstructorFlat(constructor: IrConstructor, replacement: IrReplacementFunction): List { - val worker = replacement.function - - valueMap.putAll(replacement.valueParameterMap) - worker.valueParameters.forEach { it.transformChildrenVoid() } - worker.body = context.createIrBuilder(worker.symbol, worker.startOffset, worker.endOffset).irBlockBody(worker) { + private fun transformConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List { + replacement.valueParameters.forEach { it.transformChildrenVoid() } + replacement.body = context.createIrBuilder(replacement.symbol, replacement.startOffset, replacement.endOffset).irBlockBody( + replacement + ) { val thisVar = irTemporaryVarDeclaration( - worker.returnType, nameHint = "\$this", isMutable = false + replacement.returnType, nameHint = "\$this", isMutable = false ) valueMap[constructor.constructedClass.thisReceiver!!.symbol] = thisVar @@ -189,13 +193,13 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F } }, null) .transform(this@JvmInlineClassLowering, null) - .patchDeclarationParents(worker) + .patchDeclarationParents(replacement) } +irReturn(irGet(thisVar)) } - return listOf(worker) + return listOf(replacement) } private fun typedArgumentList(function: IrFunction, expression: IrMemberAccessExpression) = @@ -207,31 +211,27 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F private fun IrMemberAccessExpression.buildReplacement( originalFunction: IrFunction, original: IrMemberAccessExpression, - replacement: IrReplacementFunction + replacement: IrSimpleFunction ) { copyTypeArgumentsFrom(original) + val valueParameterMap = originalFunction.explicitParameters.zip(replacement.explicitParameters).toMap() for ((parameter, argument) in typedArgumentList(originalFunction, original)) { if (argument == null) continue - val newParameter = replacement.valueParameterMap[parameter.symbol] ?: continue - putArgument( - replacement.function, - newParameter, - argument.transform(this@JvmInlineClassLowering, null) - ) + val newParameter = valueParameterMap.getValue(parameter) + putArgument(replacement, newParameter, argument.transform(this@JvmInlineClassLowering, null)) } } override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { - val replacement = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner) + val function = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner) ?: return super.visitFunctionReference(expression) - val function = replacement.function return IrFunctionReferenceImpl( expression.startOffset, expression.endOffset, expression.type, function.symbol, function.typeParameters.size, function.valueParameters.size, expression.reflectionTarget, expression.origin ).apply { - buildReplacement(expression.symbol.owner, expression, replacement) + buildReplacement(expression.symbol.owner, expression, function) }.copyAttributes(expression) } @@ -240,7 +240,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F val replacement = context.inlineClassReplacements.getReplacementFunction(function) ?: return super.visitFunctionAccess(expression) return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) - .irCall(replacement.function).apply { + .irCall(replacement).apply { buildReplacement(function, expression, replacement) } } @@ -278,7 +278,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(klass, context.irBuiltIns) } else { val equals = klass.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() } - this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!.function + this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!! } return irCall(equalsMethod).apply { @@ -363,7 +363,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F override fun visitReturn(expression: IrReturn): IrExpression { expression.returnTargetSymbol.owner.safeAs()?.let { target -> context.inlineClassReplacements.getReplacementFunction(target)?.let { - return context.createIrBuilder(it.function.symbol, expression.startOffset, expression.endOffset).irReturn( + return context.createIrBuilder(it.symbol, expression.startOffset, expression.endOffset).irReturn( expression.value.transform(this, null) ) } @@ -433,7 +433,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F // Add a static bridge method to the primary constructor. // This is a placeholder for null-checks and default arguments. - val function = context.inlineClassReplacements.getReplacementFunction(irConstructor)!!.function + val function = context.inlineClassReplacements.getReplacementFunction(irConstructor)!! with(context.createIrBuilder(function.symbol)) { val argument = function.valueParameters[0] function.body = irExprBody( diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStringConcatenationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStringConcatenationLowering.kt index fc02dccb884..85260cf7b74 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStringConcatenationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStringConcatenationLowering.kt @@ -107,7 +107,7 @@ private class JvmStringConcatenationLowering(val context: JvmBackendContext) : F val toStringReplacement = backendContext.inlineClassReplacements.getReplacementFunction(toStringFunction) ?: return expression - return irCall(toStringReplacement.function).apply { + return irCall(toStringReplacement).apply { putValueArgument(0, expression) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index fb4dfa9362e..852761966ca 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -19,24 +19,14 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl -import org.jetbrains.kotlin.ir.util.constructedClass -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.explicitParameters -import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.utils.addToStdlib.safeAs -class IrReplacementFunction( - val function: IrFunction, - val valueParameterMap: Map -) - /** * Keeps track of replacement functions and inline class box/unbox functions. */ @@ -46,7 +36,7 @@ class MemoizedInlineClassReplacements { /** * Get a replacement for a function or a constructor. */ - val getReplacementFunction: (IrFunction) -> IrReplacementFunction? = + val getReplacementFunction: (IrFunction) -> IrSimpleFunction? = storageManager.createMemoizedFunctionWithNullableValues { when { !it.hasMangledParameters || @@ -135,18 +125,12 @@ class MemoizedInlineClassReplacements { } } - private fun createMethodReplacement(function: IrFunction): IrReplacementFunction? { - require(function.dispatchReceiverParameter != null && function is IrSimpleFunction) - val overrides = function.overriddenSymbols.mapNotNull { - getReplacementFunction(it.owner)?.function?.symbol as? IrSimpleFunctionSymbol - } - if (function.origin == IrDeclarationOrigin.FAKE_OVERRIDE && overrides.isEmpty()) - return null - - val parameterMap = mutableMapOf() - val replacement = buildReplacement(function) { - metadata = function.metadata - overriddenSymbols += overrides + private fun createMethodReplacement(function: IrFunction): IrSimpleFunction = + buildReplacement(function) { + require(function.dispatchReceiverParameter != null && function is IrSimpleFunction) + overriddenSymbols = function.overriddenSymbols.map { + getReplacementFunction(it.owner)?.symbol ?: it + } val newValueParameters = ArrayList() for ((index, parameter) in function.explicitParameters.withIndex()) { @@ -162,24 +146,14 @@ class MemoizedInlineClassReplacements { // Assuming that constructors and non-override functions are always replaced with the unboxed // equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`. newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this) - parameterMap[parameter.symbol] = newParameter } valueParameters = newValueParameters } - return IrReplacementFunction(replacement, parameterMap) - } - private fun createStaticReplacement(function: IrFunction): IrReplacementFunction { - val parameterMap = mutableMapOf() - val replacement = buildReplacement(function) { - // Generate metadata for the replacement function instead of the original. - if (function is IrFunctionBase<*>) { - metadata = function.metadata - function.metadata = null - } - - - valueParameters += function.explicitParameters.mapIndexed { index, parameter -> + private fun createStaticReplacement(function: IrFunction): IrSimpleFunction = + buildReplacement(function) { + val newValueParameters = ArrayList() + for ((index, parameter) in function.explicitParameters.withIndex()) { val name = when (parameter) { function.dispatchReceiverParameter -> Name.identifier("arg$index") function.extensionReceiverParameter -> Name.identifier("\$this\$${function.name}") @@ -191,16 +165,12 @@ class MemoizedInlineClassReplacements { else -> parameter.origin } val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null, origin = parameterOrigin) - valueParameters += newParameter + newValueParameters += newParameter // See comment next to a similar line above. newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this) - parameterMap[parameter.symbol] = newParameter - - newParameter } + valueParameters = newValueParameters } - return IrReplacementFunction(replacement, parameterMap) - } private fun buildReplacement(function: IrFunction, body: IrFunctionImpl.() -> Unit) = buildFunWithDescriptorForInlining(function.descriptor) { @@ -213,12 +183,10 @@ class MemoizedInlineClassReplacements { }.apply { parent = function.parent annotations += function.annotations - if (function is IrConstructor) { - copyTypeParameters(function.constructedClass.typeParameters + function.typeParameters) - } else { - copyTypeParametersFrom(function) - correspondingPropertySymbol = function.safeAs()?.correspondingPropertySymbol - } + copyTypeParameters(function.allTypeParameters) + correspondingPropertySymbol = function.safeAs()?.correspondingPropertySymbol + metadata = function.metadata + function.safeAs>()?.metadata = null body() } } diff --git a/compiler/testData/codegen/box/inlineClasses/functionNameMangling/overridingMethodInGenericClass2.kt b/compiler/testData/codegen/box/inlineClasses/functionNameMangling/overridingMethodInGenericClass2.kt index 53b2b0a64d0..7e3e4dc95a7 100644 --- a/compiler/testData/codegen/box/inlineClasses/functionNameMangling/overridingMethodInGenericClass2.kt +++ b/compiler/testData/codegen/box/inlineClasses/functionNameMangling/overridingMethodInGenericClass2.kt @@ -1,5 +1,6 @@ // !LANGUAGE: +InlineClasses // IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JVM_IR abstract class GenericBase { abstract fun foo(x: T): T @@ -21,4 +22,4 @@ fun box(): String { if (Derived().foo("OK") != "OK") throw AssertionError() return "OK" -} \ No newline at end of file +}