diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt index 7f8b4905de9..b63dce302b6 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt @@ -356,7 +356,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV } override fun handleSpecificNewClass(declaration: IrClass) { - val rootNode = replacements.getRootMfvcNode(declaration)!! + val rootNode = replacements.getRootMfvcNode(declaration) rootNode.replaceFields() declaration.declarations.removeIf { it is IrSimpleFunction && it.isMultiFieldValueClassFieldGetter && it.overriddenSymbols.isEmpty() } declaration.declarations += rootNode.run { allUnboxMethods + listOf(boxMethod, specializedEqualsMethod) } @@ -376,7 +376,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV override fun visitClass(declaration: IrClass): IrStatement = declaration override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { - val oldPrimaryConstructor = replacements.getRootMfvcNode(constructor.constructedClass)!!.oldPrimaryConstructor + val oldPrimaryConstructor = replacements.getRootMfvcNode(constructor.constructedClass).oldPrimaryConstructor thisVar.initializer = irCall(oldPrimaryConstructor).apply { copyTypeAndValueArgumentsFrom(expression) } @@ -720,7 +720,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV function is IrConstructor && function.isPrimary && function.constructedClass.isMultiFieldValueClass && currentScope.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER -> { context.createIrBuilder(currentScope.symbol).irBlock { - val rootNode = replacements.getRootMfvcNode(function.constructedClass)!! + val rootNode = replacements.getRootMfvcNode(function.constructedClass) val instance = rootNode.createInstanceFromValueDeclarationsAndBoxType( this, function.constructedClassType as IrSimpleType, Name.identifier("constructor_tmp"), ::variablesSaver ) @@ -769,9 +769,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV val leftArgument = expression.getValueArgument(0)!! val rightArgument = expression.getValueArgument(1)!! val leftClass = leftArgument.type.erasedUpperBound - val leftNode = if (leftArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNode(leftClass) else null + val leftNode = if (leftArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNodeOrNull(leftClass) else null val rightClass = rightArgument.type.erasedUpperBound - val rightNode = if (rightArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNode(rightClass) else null + val rightNode = if (rightArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNodeOrNull(rightClass) else null if (leftNode != null) { if (rightNode != null) { // both are unboxed @@ -1013,7 +1013,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV val initializer = declaration.initializer if (declaration.type.needsMfvcFlattening()) { val irClass = declaration.type.erasedUpperBound - val rootNode = replacements.getRootMfvcNode(irClass)!! + val rootNode = replacements.getRootMfvcNode(irClass) return context.createIrBuilder(getCurrentScopeSymbol()).irBlock { val instance = rootNode.createInstanceFromValueDeclarationsAndBoxType( this, declaration.type as IrSimpleType, declaration.name, ::variablesSaver @@ -1036,7 +1036,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV if (!expression.type.needsMfvcFlattening()) { return listOf(expression.transform(this@JvmMultiFieldValueClassLowering, null)) } - val rootMfvcNode = replacements.getRootMfvcNode(expression.type.erasedUpperBound)!! + val rootMfvcNode = replacements.getRootMfvcNode(expression.type.erasedUpperBound) val typeArguments = makeTypeArgumentsFromType(expression.type as IrSimpleType) val variables = rootMfvcNode.leaves.map { savableStandaloneVariable( @@ -1060,7 +1060,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV * Takes not transformed expression and initialized given MfvcNodeInstance with transformed version of it */ fun IrBlockBuilder.flattenExpressionTo(expression: IrExpression, instance: MfvcNodeInstance) { - val rootNode = replacements.getRootMfvcNode( + val rootNode = replacements.getRootMfvcNodeOrNull( if (expression is IrConstructorCall) expression.symbol.owner.constructedClass else expression.type.erasedUpperBound ) val type = if (expression is IrConstructorCall) expression.symbol.owner.constructedClass.defaultType else expression.type @@ -1198,7 +1198,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV val statementsToRemove = mutableSetOf() for (statement in expression.statements.subListWithoutLast(if (resultIsUsed) 1 else 0)) { val call = getFunctionCallOrNull(statement) ?: continue - val node = replacements.getRootMfvcNode(call.type.erasedUpperBound) ?: continue + val node = replacements.getRootMfvcNodeOrNull(call.type.erasedUpperBound) ?: continue if (node.boxMethod == call.symbol.owner && List(call.valueArgumentsCount) { call.getValueArgument(it) }.all { it.isRepeatableGetter() } ) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt index 18946ae017f..b0abc70b7fa 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt @@ -21,7 +21,6 @@ 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 -import org.jetbrains.kotlin.utils.alwaysNull import java.util.concurrent.ConcurrentHashMap /** @@ -31,8 +30,7 @@ class MemoizedInlineClassReplacements( private val mangleReturnTypes: Boolean, irFactory: IrFactory, context: JvmBackendContext -) : MemoizedValueClassAbstractReplacements(irFactory, context) { - private val storageManager = LockBasedStorageManager("inline-class-replacements") +) : MemoizedValueClassAbstractReplacements(irFactory, context, LockBasedStorageManager("inline-class-replacements")) { val originalFunctionForStaticReplacement: MutableMap = ConcurrentHashMap() val originalFunctionForMethodReplacement: MutableMap = ConcurrentHashMap() @@ -40,7 +38,7 @@ class MemoizedInlineClassReplacements( /** * Get a replacement for a function or a constructor. */ - override val getReplacementFunction: (IrFunction) -> IrSimpleFunction? = + override val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? = storageManager.createMemoizedFunctionWithNullableValues { when { // Don't mangle anonymous or synthetic functions, except for generated SAM wrapper methods @@ -68,9 +66,11 @@ class MemoizedInlineClassReplacements( it.isRemoveAtSpecialBuiltinStub() -> null + it.isValueClassMemberFakeOverriddenFromJvmDefaultInterfaceMethod() || it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB -> createMethodReplacement(it) + else -> createStaticReplacement(it) } @@ -85,6 +85,13 @@ class MemoizedInlineClassReplacements( } } + override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction) = !( + function.parent.let { (it is IrClass && it.isSingleFieldValueClass) } || + function.dispatchReceiverParameter?.type?.isInlineClassType() == true || + function.extensionReceiverParameter?.type?.isInlineClassType() == true || + function.valueParameters.any { it.type.isInlineClassType() } || function.returnType.isInlineClassType() + ) + /** * Get the box function for an inline class. Concretely, this is a synthetic * static function named "box-impl" which takes an unboxed value and returns @@ -246,20 +253,15 @@ class MemoizedInlineClassReplacements( origin = when { function.origin == IrDeclarationOrigin.GENERATED_SINGLE_FIELD_VALUE_CLASS_MEMBER -> JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD + function is IrConstructor && function.constructedClass.isSingleFieldValueClass -> JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR + else -> replacementOrigin } name = InlineClassAbi.mangledNameFor(function, mangleReturnTypes, useOldManglingScheme) } - override val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? = alwaysNull() - - override val replaceOverriddenSymbols: (IrSimpleFunction) -> List = - storageManager.createMemoizedFunction { irSimpleFunction -> - irSimpleFunction.overriddenSymbols.map { - computeOverrideReplacement(it.owner).symbol - } - } + override fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor? = null } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt index 36cbf6953c0..5b4f16e7d8d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.builders.irExprBody import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType @@ -31,8 +30,7 @@ import java.util.concurrent.ConcurrentHashMap class MemoizedMultiFieldValueClassReplacements( irFactory: IrFactory, context: JvmBackendContext -) : MemoizedValueClassAbstractReplacements(irFactory, context) { - private val storageManager = LockBasedStorageManager("multi-field-value-class-replacements") +) : MemoizedValueClassAbstractReplacements(irFactory, context, LockBasedStorageManager("multi-field-value-class-replacements")) { val originalFunctionForStaticReplacement: MutableMap = ConcurrentHashMap() val originalFunctionForMethodReplacement: MutableMap = ConcurrentHashMap() @@ -224,7 +222,7 @@ class MemoizedMultiFieldValueClassReplacements( /** * Get a function replacement for a function or a constructor. */ - override val getReplacementFunction: (IrFunction) -> IrSimpleFunction? = + override val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? = storageManager.createMemoizedFunctionWithNullableValues { function -> when { (function.isLocal && function is IrSimpleFunction && function.overriddenSymbols.isEmpty()) || @@ -259,6 +257,13 @@ class MemoizedMultiFieldValueClassReplacements( } } + override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean = !( + function.parent.let { it is IrClass && it.isMultiFieldValueClass } || + function.dispatchReceiverParameter?.type?.needsMfvcFlattening() == true || + function.extensionReceiverParameter?.type?.needsMfvcFlattening() == true || + function.valueParameters.any { it.type.needsMfvcFlattening() } + ) + private fun makeMultiFieldValueClassFieldGetterReplacement(function: IrFunction): IrSimpleFunction { require(function is IrSimpleFunction && function.isMultiFieldValueClassFieldGetter) { "Illegal function:\n${function.dump()}" } val replacement = getMfvcPropertyNode(function.correspondingPropertySymbol!!.owner)!!.unboxMethod @@ -269,48 +274,51 @@ class MemoizedMultiFieldValueClassReplacements( return replacement } - override val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? = + private val getReplacementForRegularClassConstructorImpl: (IrConstructor) -> IrConstructor? = storageManager.createMemoizedFunctionWithNullableValues { constructor -> when { - constructor.constructedClass.isMultiFieldValueClass -> null - constructor.isFromJava() -> null - constructor.fullValueParameterList.any { it.type.needsMfvcFlattening() } -> - createConstructorReplacement(constructor) - - else -> null + constructor.isFromJava() -> null //is recursive so run once + else -> createConstructorReplacement(constructor) } } - - override val replaceOverriddenSymbols: (IrSimpleFunction) -> List = - storageManager.createMemoizedFunction { irSimpleFunction -> - irSimpleFunction.overriddenSymbols.map { - computeOverrideReplacement(it.owner).symbol - } - } - - val getRootMfvcNode: (IrClass) -> RootMfvcNode? = storageManager.createMemoizedFunctionWithNullableValues { - if (it.defaultType.needsMfvcFlattening()) getRootNode(context, it) else null + override fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor? = when { + constructor.constructedClass.isMultiFieldValueClass -> null + constructor.valueParameters.none { it.type.needsMfvcFlattening() } -> null + else -> getReplacementForRegularClassConstructorImpl(constructor) } - val getRegularClassMfvcPropertyNode: (IrProperty) -> IntermediateMfvcNode? = - storageManager.createMemoizedFunctionWithNullableValues { property: IrProperty -> - val parent = property.parent - when { - parent !is IrClass -> null - property.isFakeOverride -> null - property.getter.let { it != null && (it.contextReceiverParametersCount > 0 || it.extensionReceiverParameter != null) } -> null - useRootNode(parent, property) -> null - property.run { backingField?.type ?: getter?.returnType }?.needsMfvcFlattening() != true -> null - else -> createIntermediateNodeForMfvcPropertyOfRegularClass(parent, context, property) - } + val getRootMfvcNode: (IrClass) -> RootMfvcNode = storageManager.createMemoizedFunction { + require(it.defaultType.needsMfvcFlattening()) { it.defaultType.render() } + getRootNode(context, it) + } + + fun getRootMfvcNodeOrNull(irClass: IrClass): RootMfvcNode? = + if (irClass.defaultType.needsMfvcFlattening()) getRootMfvcNode(irClass) else null + + private val getRegularClassMfvcPropertyNodeImpl: (IrProperty) -> IntermediateMfvcNode = + storageManager.createMemoizedFunction { property: IrProperty -> + val parent = property.parentAsClass + createIntermediateNodeForMfvcPropertyOfRegularClass(parent, context, property) } + fun getRegularClassMfvcPropertyNode(property: IrProperty): IntermediateMfvcNode? { + val parent = property.parent + return when { + property.run { backingField?.type ?: getter?.returnType }?.needsMfvcFlattening() != true -> null + parent !is IrClass -> null + property.isFakeOverride -> null + property.getter.let { it != null && (it.contextReceiverParametersCount > 0 || it.extensionReceiverParameter != null) } -> null + useRootNode(parent, property) -> null + else -> getRegularClassMfvcPropertyNodeImpl(property) + } + } + fun getMfvcPropertyNode(property: IrProperty): NameableMfvcNode? { val parent = property.parent return when { parent !is IrClass -> null - useRootNode(parent, property) -> getRootMfvcNode(parent)!![property.name] + useRootNode(parent, property) -> getRootMfvcNode(parent)[property.name] else -> getRegularClassMfvcPropertyNode(property) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt index 1c7536e77cf..3137cf29c7c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt @@ -16,15 +16,23 @@ import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.isInt import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.storage.LockBasedStorageManager import java.util.concurrent.ConcurrentHashMap -abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: IrFactory, protected val context: JvmBackendContext) { +abstract class MemoizedValueClassAbstractReplacements( + protected val irFactory: IrFactory, + protected val context: JvmBackendContext, + protected val storageManager: LockBasedStorageManager +) { private val propertyMap = ConcurrentHashMap() /** * Get a replacement for a function or a constructor. */ - abstract val getReplacementFunction: (IrFunction) -> IrSimpleFunction? + fun getReplacementFunction(function: IrFunction) = + if (quickCheckIfFunctionIsNotApplicable(function)) null else getReplacementFunctionImpl(function) + + protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? protected fun IrFunction.isRemoveAtSpecialBuiltinStub() = origin == IrDeclarationOrigin.IR_BUILTINS_STUB && @@ -106,12 +114,23 @@ abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: I body() } - abstract val replaceOverriddenSymbols: (IrSimpleFunction) -> List + private val replaceOverriddenSymbolsImpl: (IrSimpleFunction) -> List = + storageManager.createMemoizedFunction { irSimpleFunction -> + irSimpleFunction.overriddenSymbols.map { + computeOverrideReplacement(it.owner).symbol + } + } - abstract val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? + fun replaceOverriddenSymbols(function: IrSimpleFunction): List = + if (function.overriddenSymbols.isEmpty()) listOf() + else replaceOverriddenSymbolsImpl(function) - protected fun computeOverrideReplacement(function: IrSimpleFunction): IrSimpleFunction = + abstract fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor? + + private fun computeOverrideReplacement(function: IrSimpleFunction): IrSimpleFunction = getReplacementFunction(function) ?: function.also { function.overriddenSymbols = replaceOverriddenSymbols(function) } + + protected abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean } \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt index c4de0207f1b..4a5504b52fe 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt @@ -188,7 +188,7 @@ fun createIntermediateMfvcNode( val representation = valueClass.multiFieldValueClassRepresentation!! val replacements = context.multiFieldValueClassReplacements - val rootNode = replacements.getRootMfvcNode(valueClass)!! + val rootNode = replacements.getRootMfvcNode(valueClass) val oldField = oldGetter?.correspondingPropertySymbol?.owner?.backingField