diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt index 5768a82c021..028a5d1350b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt @@ -30,7 +30,7 @@ open class ScopeWithIr(val scope: Scope, val irElement: IrElement) abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() { - private val scopeStack = mutableListOf() + protected open val scopeStack = mutableListOf() protected open fun createScope(declaration: IrSymbolOwner): ScopeWithIr = ScopeWithIr(Scope(declaration.symbol), declaration) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt index a618d81b91b..11fdf90049a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FinallyBlocksLowering.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl -import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isUnit @@ -75,14 +74,14 @@ class FinallyBlocksLowering(val context: CommonBackendContext, private val throw val jumps = mutableMapOf() } - private val scopeStack = mutableListOf() + private val otherScopeStack = mutableListOf() private inline fun using(scope: S, block: (S) -> R): R { - scopeStack.push(scope) + otherScopeStack.push(scope) try { return block(scope) } finally { - scopeStack.pop() + otherScopeStack.pop() } } @@ -155,7 +154,7 @@ class FinallyBlocksLowering(val context: CommonBackendContext, private val throw endOffset: Int, value: IrExpression ): IrExpression? { - val tryScopes = scopeStack.reversed() + val tryScopes = otherScopeStack.reversed() .takeWhile { !targetScopePredicate(it) } .filterIsInstance() .toList() diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 7c9cc00df4e..88ab849336a 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -310,8 +310,7 @@ private val jvmFilePhases = listOf( forLoopsPhase, collectionStubMethodLowering, singleAbstractMethodPhase, - jvmMultiFieldValueClassPhase, - jvmInlineClassPhase, + jvmValueClassPhase, tailrecPhase, // makePatchParentsPhase(), diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index e07b8e2975a..b9b2db8e741 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -113,7 +113,7 @@ internal val bridgePhase = makeIrFilePhase( ::BridgeLowering, name = "Bridge", description = "Generate bridges", - prerequisite = setOf(jvmInlineClassPhase, jvmMultiFieldValueClassPhase, inheritedDefaultMethodsOnClassesPhase) + prerequisite = setOf(jvmValueClassPhase, inheritedDefaultMethodsOnClassesPhase) ) internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt index 3441e08e92c..eb572a52cfd 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt @@ -5,12 +5,12 @@ package org.jetbrains.kotlin.backend.jvm.lower +import org.jetbrains.kotlin.backend.common.ScopeWithIr import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlockBody -import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase -import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.* import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound +import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.descriptors.DescriptorVisibilities @@ -31,28 +31,19 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME -val jvmInlineClassPhase = makeIrFilePhase( - ::JvmInlineClassLowering, - name = "Inline Classes", - description = "Lower inline classes", - // forLoopsPhase may produce UInt and ULong which are inline classes. - // Standard library replacements are done on the unmangled names for UInt and ULong classes. - // Collection stubs may require mangling by inline class rules. - // SAM wrappers may require mangling for fun interfaces with inline class parameters - prerequisite = setOf( - forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase, jvmMultiFieldValueClassPhase - ), -) - /** * Adds new constructors, box, and unbox functions to inline classes as well as replacement - * functions and bridges to avoid clashes between overloaded function. Changes calls with + * functions and bridges to avoid clashes between overloaded function. Changes call with * known types to call the replacement functions. * * We do not unfold inline class types here. Instead, the type mapper will lower inline class * types to the types of their underlying field. */ -private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) { +internal class JvmInlineClassLowering( + context: JvmBackendContext, + fileClassNewDeclarations: MutableMap>, + scopeStack: MutableList, +) : JvmValueClassAbstractLowering(context, fileClassNewDeclarations, scopeStack) { override val replacements: MemoizedValueClassAbstractReplacements get() = context.inlineClassReplacements @@ -83,8 +74,10 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass override val specificMangle: SpecificMangle get() = SpecificMangle.Inline + override val IrType.needsHandling get() = isInlineClassType() + override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = Unit - override fun visitClassNew(declaration: IrClass): IrStatement { + override fun visitClassNew(declaration: IrClass): IrClass { // The arguments to the primary constructor are in scope in the initializers of IrFields. declaration.primaryConstructor?.let { @@ -122,7 +115,7 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass addJvmInlineAnnotation(declaration) } - fun addJvmInlineAnnotation(valueClass: IrClass) { + private fun addJvmInlineAnnotation(valueClass: IrClass) { if (valueClass.hasAnnotation(JVM_INLINE_ANNOTATION_FQ_NAME)) return val constructor = context.ir.symbols.jvmInlineAnnotation.constructors.first() valueClass.annotations = valueClass.annotations + IrConstructorCallImpl.fromSymbolOwner( @@ -424,7 +417,7 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass return super.visitSetValue(expression) } - fun buildPrimaryInlineClassConstructor(valueClass: IrClass, irConstructor: IrConstructor) { + private fun buildPrimaryInlineClassConstructor(valueClass: IrClass, irConstructor: IrConstructor) { // Add the default primary constructor valueClass.addConstructor { updateFrom(irConstructor) @@ -469,7 +462,7 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass valueClass.declarations += function } - fun buildBoxFunction(valueClass: IrClass) { + private fun buildBoxFunction(valueClass: IrClass) { val function = context.inlineClassReplacements.getBoxFunction(valueClass) with(context.createIrBuilder(function.symbol)) { function.body = irExprBody( @@ -494,7 +487,7 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass irClass.declarations += function } - fun buildSpecializedEqualsMethodIfNeeded(valueClass: IrClass) { + private fun buildSpecializedEqualsMethodIfNeeded(valueClass: IrClass) { val function = context.inlineClassReplacements.getSpecializedEqualsMethod(valueClass, context.irBuiltIns) // Return if we have already built specialized equals as static replacement of typed equals if (function.body != null) return 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 17cd00bd7e2..6b3908cd774 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 @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.ScopeWithIr import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irCatch -import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.jvm.* @@ -36,16 +35,14 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name -val jvmMultiFieldValueClassPhase = makeIrFilePhase( - ::JvmMultiFieldValueClassLowering, - name = "Multi-field Value Classes", - description = "Lower multi-field value classes", - // Collection stubs may require mangling by multi-field value class rules. - // SAM wrappers may require mangling for fun interfaces with multi-field value class parameters - prerequisite = setOf(collectionStubMethodLowering, singleAbstractMethodPhase), -) +internal class JvmMultiFieldValueClassLowering( + context: JvmBackendContext, + fileClassNewDeclarations: MutableMap>, + scopeStack: MutableList, +) : JvmValueClassAbstractLowering(context, fileClassNewDeclarations, scopeStack) { + override val IrType.needsHandling: Boolean + get() = needsMfvcFlattening() -private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) { private sealed class MfvcNodeInstanceAccessor { abstract val instance: MfvcNodeInstance abstract operator fun get(name: Name): MfvcNodeInstanceAccessor? @@ -268,7 +265,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV variablesToAdd.getOrPut(variable.parent) { mutableSetOf() }.add(variable) } - override fun visitClassNew(declaration: IrClass): IrStatement { + override fun visitClassNew(declaration: IrClass): IrClass { if (declaration.isSpecificLoweringLogicApplicable()) { handleSpecificNewClass(declaration) @@ -284,25 +281,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV null }).also { declarations -> for (replacingDeclaration in declarations ?: listOf(memberDeclaration)) { - when (replacingDeclaration) { - is IrFunction -> replacingDeclaration.body = replacingDeclaration.body?.makeBodyWithAddedVariables( - context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol - )?.apply { - if (replacingDeclaration in possibleExtraBoxUsageGenerated) { - removeAllExtraBoxes() - } - } - - is IrAnonymousInitializer -> replacingDeclaration.body = replacingDeclaration.body.makeBodyWithAddedVariables( - context, variablesToAdd[replacingDeclaration.parent] ?: emptySet(), replacingDeclaration.symbol - ).apply { - if (replacingDeclaration in possibleExtraBoxUsageGenerated) { - removeAllExtraBoxes() - } - } as IrBlockBody - - else -> Unit - } + postActionAfterTransformingClassDeclaration(replacingDeclaration) } } } @@ -310,6 +289,31 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV return declaration } + override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = + postActionAfterTransformingClassDeclaration(declaration) + + private fun postActionAfterTransformingClassDeclaration(replacingDeclaration: IrDeclaration) { + when (replacingDeclaration) { + is IrFunction -> replacingDeclaration.body = replacingDeclaration.body?.makeBodyWithAddedVariables( + context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol + )?.apply { + if (replacingDeclaration in possibleExtraBoxUsageGenerated) { + removeAllExtraBoxes() + } + } + + is IrAnonymousInitializer -> replacingDeclaration.body = replacingDeclaration.body.makeBodyWithAddedVariables( + context, variablesToAdd[replacingDeclaration.parent] ?: emptySet(), replacingDeclaration.symbol + ).apply { + if (replacingDeclaration in possibleExtraBoxUsageGenerated) { + removeAllExtraBoxes() + } + } as IrBlockBody + + else -> Unit + } + } + private fun handleNonSpecificNewClass(irClass: IrClass) { irClass.primaryConstructor?.let { replacements.getReplacementForRegularClassConstructor(it)?.let { replacement -> addBindingsFor(it, replacement) } @@ -319,7 +323,8 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV val property = (propertyOrField as? IrPropertyOrIrField.Property)?.property ?: return@mapNotNull null property.backingField?.let { property to it } }.toMap() - val propertiesOrFieldsReplacement = collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields) // resets backing fields + val propertiesOrFieldsReplacement = + collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields) // resets backing fields val fieldsToRemove = propertiesOrFieldsReplacement.keys.mapNotNull { when (it) { @@ -696,7 +701,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV } } - fun RootMfvcNode.replacePrimaryMultiFieldValueClassConstructor() { + private fun RootMfvcNode.replacePrimaryMultiFieldValueClassConstructor() { val rootMfvcNode = this mfvc.declarations.removeIf { it is IrConstructor && it.isPrimary } mfvc.declarations += listOf(newPrimaryConstructor, primaryConstructorImpl) @@ -755,26 +760,28 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV } } - override val fileClassNewDeclarations = mutableMapOf>() - - private fun createMfvcPrimaryConstructorReferenceHelperFunction(rootNode: RootMfvcNode) = context.irFactory.buildFun { - name = Name.identifier("mfvcConstructorReferenceHelper\$${fileClassNewDeclarations[currentFile]?.size ?: 0}") - origin = JvmLoweredDeclarationOrigin.MFVC_PRIMARY_CONSTRUCTOR_REFERENCE_HELPER - }.apply function@{ - fileClassNewDeclarations.getOrPut(currentFile) { mutableListOf() }.add(this) - copyParameterDeclarationsFrom(rootNode.primaryConstructorImpl) - returnType = rootNode.type.substitute(rootNode.mfvc.typeParameters, typeParameters.map { it.defaultType }) - body = context.createJvmIrBuilder(this.symbol).run { - irExprBody(irBlock { - for (callee in listOf(rootNode.primaryConstructorImpl, rootNode.boxMethod)) { - +irCall(callee).apply { - passTypeArgumentsFrom(this@function) - for ((index, parameter) in this@function.valueParameters.withIndex()) { - putValueArgument(index, irGet(parameter)) + private fun createMfvcPrimaryConstructorReferenceHelperFunction(rootNode: RootMfvcNode): IrSimpleFunction { + val currentFile = currentFile + return context.irFactory.buildFun { + name = Name.identifier("mfvcConstructorReferenceHelper\$${fileClassNewDeclarations[currentFile]?.size ?: 0}") + origin = JvmLoweredDeclarationOrigin.MFVC_PRIMARY_CONSTRUCTOR_REFERENCE_HELPER + }.apply function@{ + parent = currentFile + fileClassNewDeclarations.getOrPut(currentFile) { mutableListOf() }.add(this) + copyParameterDeclarationsFrom(rootNode.primaryConstructorImpl) + returnType = rootNode.type.substitute(rootNode.mfvc.typeParameters, typeParameters.map { it.defaultType }) + body = context.createJvmIrBuilder(this.symbol).run { + irExprBody(irBlock { + for (callee in listOf(rootNode.primaryConstructorImpl, rootNode.boxMethod)) { + +irCall(callee).apply { + passTypeArgumentsFrom(this@function) + for ((index, parameter) in this@function.valueParameters.withIndex()) { + putValueArgument(index, irGet(parameter)) + } } } - } - }) + }) + } } } @@ -971,7 +978,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV * val b = 3 * [a, b, b + 1] */ - fun IrBuilderWithScope.removeExtraSetVariablesFromExpressionList( + private fun IrBuilderWithScope.removeExtraSetVariablesFromExpressionList( block: IrContainerExpression, variables: List ): List { @@ -1114,7 +1121,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) { + private fun IrBlockBuilder.flattenExpressionTo(expression: IrExpression, instance: MfvcNodeInstance) { val rootNode = replacements.getRootMfvcNodeOrNull( if (expression is IrConstructorCall) expression.symbol.owner.constructedClass else expression.type.erasedUpperBound ) @@ -1197,7 +1204,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV /** * Removes boxing when the result is not used */ - fun IrBody.removeAllExtraBoxes() { + private fun IrBody.removeAllExtraBoxes() { // data is whether the expression result is used accept(object : IrElementVisitor { override fun visitElement(element: IrElement, data: Boolean) { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt index b7f016c87b4..33c7e1ceaee 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt @@ -5,44 +5,37 @@ package org.jetbrains.kotlin.backend.jvm.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.pop -import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.jvm.* +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.transformStatement +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd import org.jetbrains.kotlin.utils.addToStdlib.safeAs -internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendContext) : FileLoweringPass, - IrElementTransformerVoidWithContext() { +internal abstract class JvmValueClassAbstractLowering( + val context: JvmBackendContext, + protected val fileClassNewDeclarations: MutableMap>, + override val scopeStack: MutableList, +) : FileLoweringPass, IrElementTransformerVoidWithContext() { abstract val replacements: MemoizedValueClassAbstractReplacements - final override fun lower(irFile: IrFile) { - withinScope(irFile) { - irFile.transformChildrenVoid() - fileClassNewDeclarations[irFile]?.let { newDeclarations -> - val oldFileClass = irFile.declarations.filterIsInstanceAnd { it.isFileClass }.singleOrNull() - val allFileDeclarations = (oldFileClass?.declarations ?: listOf()) + newDeclarations - val newClass = createFileClass(context, irFile, allFileDeclarations) - oldFileClass?.let { irFile.declarations.remove(it) } - irFile.addChild(newClass) - } - } + final override fun lower(irFile: IrFile) = withinScope(irFile) { + irFile.transformChildrenVoid() + addDeclarations(context, fileClassNewDeclarations, irFile) } abstract fun IrClass.isSpecificLoweringLogicApplicable(): Boolean - abstract override fun visitClassNew(declaration: IrClass): IrStatement - abstract fun handleSpecificNewClass(declaration: IrClass) protected fun transformFunctionFlat(function: IrFunction): List? { @@ -91,7 +84,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon } } - private fun transformFlattenedConstructor(function: IrConstructor, replacement: IrConstructor): List? { + private fun transformFlattenedConstructor(function: IrConstructor, replacement: IrConstructor): List { replacement.valueParameters.forEach { visitParameter(it) it.defaultValue?.patchDeclarationParents(replacement) @@ -155,7 +148,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon return super.visitReturn(expression) } - private fun visitStatementContainer(container: IrStatementContainer) { + internal fun visitStatementContainer(container: IrStatementContainer) { container.statements.transformFlat { statement -> if (statement is IrFunction) transformFunctionFlat(statement) @@ -248,5 +241,157 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon protected abstract fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean) - protected open val fileClassNewDeclarations: Map> = emptyMap() + + // Functions for common lowering dispatching + private inner class NeedsToVisit : IrElementVisitor { + override fun visitElement(element: IrElement, data: Nothing?): Boolean = false + override fun visitClass(declaration: IrClass, data: Nothing?): Boolean = + declaration.isSpecificLoweringLogicApplicable() || declaration.declarations.any { it.accept(this, null) } + + override fun visitFunction(declaration: IrFunction, data: Nothing?): Boolean = + replacements.quickCheckIfFunctionIsNotApplicable(declaration) + + override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean = + visitFunction(expression.symbol.owner, data) + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean = + visitFunction(expression.symbol.owner, data) + + override fun visitField(declaration: IrField, data: Nothing?): Boolean = declaration.type.needsHandling + override fun visitFieldAccess(expression: IrFieldAccessExpression, data: Nothing?): Boolean = + visitField(expression.symbol.owner, data) + + override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean = visitValueDeclaration(declaration) + + private fun visitValueDeclaration(declaration: IrValueDeclaration) = declaration.type.needsHandling + override fun visitValueParameter(declaration: IrValueParameter, data: Nothing?): Boolean = visitValueDeclaration(declaration) + override fun visitValueAccess(expression: IrValueAccessExpression, data: Nothing?): Boolean = + visitValueDeclaration(expression.symbol.owner) + + override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean = false + override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean = expression.returnTargetSymbol.owner.safeAs() + ?.let { replacements.quickCheckIfFunctionIsNotApplicable(it) } ?: false + + override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): Boolean = + declaration.parent.safeAs()?.isSpecificLoweringLogicApplicable() == true + + private fun visitStatementContainer(container: IrStatementContainer) = container.statements.any { it.accept(this, null) } + + override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean = + visitStatementContainer(expression) + + override fun visitBlockBody(body: IrBlockBody, data: Nothing?): Boolean = visitStatementContainer(body) + } + + internal fun needsToVisitClassNew(declaration: IrClass): Boolean = declaration.accept(NeedsToVisit(), null) + + internal fun needsToVisitFunctionReference(expression: IrFunctionReference): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitFunctionAccess(expression: IrFunctionAccessExpression): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitCall(expression: IrCall): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitStringConcatenation(expression: IrStringConcatenation): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitGetField(expression: IrGetField): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitSetField(expression: IrSetField): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitGetValue(expression: IrGetValue): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitSetValue(expression: IrSetValue): Boolean = expression.accept(NeedsToVisit(), null) + + internal fun needsToVisitVariable(declaration: IrVariable): Boolean = declaration.accept(NeedsToVisit(), null) + + internal fun needsToVisitReturn(expression: IrReturn): Boolean = expression.accept(NeedsToVisit(), null) + internal abstract fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) + + // forbid other overrides without modifying dispatcher file JvmValueClassLoweringDispatcher.kt + + final override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment = super.visitModuleFragment(declaration) + final override fun visitPackageFragment(declaration: IrPackageFragment): IrPackageFragment = super.visitPackageFragment(declaration) + final override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment): IrExternalPackageFragment = + super.visitExternalPackageFragment(declaration) + + final override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement = super.visitDeclaration(declaration) + final override fun visitSimpleFunction(declaration: IrSimpleFunction) = super.visitSimpleFunction(declaration) + final override fun visitConstructor(declaration: IrConstructor) = super.visitConstructor(declaration) + final override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) = super.visitLocalDelegatedProperty(declaration) + final override fun visitEnumEntry(declaration: IrEnumEntry) = super.visitEnumEntry(declaration) + final override fun visitTypeParameter(declaration: IrTypeParameter) = super.visitTypeParameter(declaration) + final override fun visitTypeAlias(declaration: IrTypeAlias) = super.visitTypeAlias(declaration) + final override fun visitBody(body: IrBody): IrBody = super.visitBody(body) + final override fun visitExpressionBody(body: IrExpressionBody) = super.visitExpressionBody(body) + final override fun visitSyntheticBody(body: IrSyntheticBody) = super.visitSyntheticBody(body) + final override fun visitSuspendableExpression(expression: IrSuspendableExpression) = super.visitSuspendableExpression(expression) + final override fun visitSuspensionPoint(expression: IrSuspensionPoint) = super.visitSuspensionPoint(expression) + final override fun visitExpression(expression: IrExpression): IrExpression = super.visitExpression(expression) + final override fun visitConst(expression: IrConst<*>) = super.visitConst(expression) + final override fun visitConstantValue(expression: IrConstantValue): IrConstantValue = super.visitConstantValue(expression) + final override fun visitConstantObject(expression: IrConstantObject) = super.visitConstantObject(expression) + final override fun visitConstantPrimitive(expression: IrConstantPrimitive) = super.visitConstantPrimitive(expression) + final override fun visitConstantArray(expression: IrConstantArray) = super.visitConstantArray(expression) + final override fun visitVararg(expression: IrVararg) = super.visitVararg(expression) + final override fun visitSpreadElement(spread: IrSpreadElement): IrSpreadElement = super.visitSpreadElement(spread) + final override fun visitBlock(expression: IrBlock) = super.visitBlock(expression) + final override fun visitComposite(expression: IrComposite) = super.visitComposite(expression) + final override fun visitDeclarationReference(expression: IrDeclarationReference) = super.visitDeclarationReference(expression) + final override fun visitSingletonReference(expression: IrGetSingletonValue) = super.visitSingletonReference(expression) + final override fun visitGetObjectValue(expression: IrGetObjectValue) = super.visitGetObjectValue(expression) + final override fun visitGetEnumValue(expression: IrGetEnumValue) = super.visitGetEnumValue(expression) + final override fun visitValueAccess(expression: IrValueAccessExpression) = super.visitValueAccess(expression) + final override fun visitFieldAccess(expression: IrFieldAccessExpression) = super.visitFieldAccess(expression) + final override fun visitMemberAccess(expression: IrMemberAccessExpression<*>) = super.visitMemberAccess(expression) + final override fun visitConstructorCall(expression: IrConstructorCall) = super.visitConstructorCall(expression) + final override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) = + super.visitDelegatingConstructorCall(expression) + + final override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) = super.visitEnumConstructorCall(expression) + final override fun visitGetClass(expression: IrGetClass) = super.visitGetClass(expression) + final override fun visitCallableReference(expression: IrCallableReference<*>) = super.visitCallableReference(expression) + final override fun visitPropertyReference(expression: IrPropertyReference) = super.visitPropertyReference(expression) + final override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) = + super.visitLocalDelegatedPropertyReference(expression) + + final override fun visitRawFunctionReference(expression: IrRawFunctionReference) = super.visitRawFunctionReference(expression) + final override fun visitFunctionExpression(expression: IrFunctionExpression) = super.visitFunctionExpression(expression) + final override fun visitClassReference(expression: IrClassReference) = super.visitClassReference(expression) + final override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) = super.visitInstanceInitializerCall(expression) + final override fun visitTypeOperator(expression: IrTypeOperatorCall) = super.visitTypeOperator(expression) + final override fun visitWhen(expression: IrWhen) = super.visitWhen(expression) + final override fun visitBranch(branch: IrBranch): IrBranch = super.visitBranch(branch) + final override fun visitElseBranch(branch: IrElseBranch): IrElseBranch = super.visitElseBranch(branch) + final override fun visitLoop(loop: IrLoop) = super.visitLoop(loop) + final override fun visitWhileLoop(loop: IrWhileLoop) = super.visitWhileLoop(loop) + final override fun visitDoWhileLoop(loop: IrDoWhileLoop) = super.visitDoWhileLoop(loop) + final override fun visitTry(aTry: IrTry) = super.visitTry(aTry) + final override fun visitCatch(aCatch: IrCatch): IrCatch = super.visitCatch(aCatch) + final override fun visitBreakContinue(jump: IrBreakContinue) = super.visitBreakContinue(jump) + final override fun visitBreak(jump: IrBreak) = super.visitBreak(jump) + final override fun visitContinue(jump: IrContinue) = super.visitContinue(jump) + final override fun visitThrow(expression: IrThrow) = super.visitThrow(expression) + final override fun visitDynamicExpression(expression: IrDynamicExpression) = super.visitDynamicExpression(expression) + final override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression) = + super.visitDynamicOperatorExpression(expression) + + final override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression) = super.visitDynamicMemberExpression(expression) + final override fun visitErrorDeclaration(declaration: IrErrorDeclaration) = super.visitErrorDeclaration(declaration) + final override fun visitErrorExpression(expression: IrErrorExpression) = super.visitErrorExpression(expression) + final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression) + + companion object { + internal fun addDeclarations( + context: JvmBackendContext, fileClassNewDeclarations: MutableMap>, irFile: IrFile + ) { + fileClassNewDeclarations[irFile]?.let { newDeclarations -> + val oldFileClass = irFile.declarations.filterIsInstanceAnd { it.isFileClass }.singleOrNull() + val allFileDeclarations = (oldFileClass?.declarations ?: listOf()) + newDeclarations + val newClass = createFileClass(context, irFile, allFileDeclarations) + oldFileClass?.let { irFile.declarations.remove(it) } + irFile.addChild(newClass) + } + } + } + + abstract val IrType.needsHandling: Boolean } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassLoweringDispatcher.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassLoweringDispatcher.kt new file mode 100644 index 00000000000..ee586ba2dc3 --- /dev/null +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassLoweringDispatcher.kt @@ -0,0 +1,193 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.transformStatement +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + +val jvmValueClassPhase = makeIrFilePhase( + ::JvmValueClassLoweringDispatcher, + name = "Value Classes", + description = "Lower value classes", + // forLoopsPhase may produce UInt and ULong which are inline classes. + // Standard library replacements are done on the not mangled names for UInt and ULong classes. + // Collection stubs may require mangling by value class rules. + // SAM wrappers may require mangling for fun interfaces with value class parameters + prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase), +) + +internal class JvmValueClassLoweringDispatcher( + private val context: JvmBackendContext, + private val fileClassNewDeclarations: MutableMap> = mutableMapOf(), + override val scopeStack: MutableList = mutableListOf(), + private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, fileClassNewDeclarations, scopeStack), + private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = + JvmMultiFieldValueClassLowering(context, fileClassNewDeclarations, scopeStack), +) : IrElementTransformerVoidWithContext(), FileLoweringPass { + + + override fun lower(irFile: IrFile) = withinScope(irFile) { + irFile.transformChildrenVoid() + JvmValueClassAbstractLowering.addDeclarations(context, fileClassNewDeclarations, irFile) + } + + + private fun IrElement.requiresAnyHandling() = + requiresHandling(multiFieldValueClassLowering) || requiresHandling(inlineClassLowering) + + override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresAnyHandling()) { + declaration + .let(multiFieldValueClassLowering::visitClassNew) + .let(inlineClassLowering::visitClassNew) + } else { + declaration.transformChildrenVoid() + for (innerDeclaration in declaration.declarations) { + multiFieldValueClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration) + } + for (innerDeclaration in declaration.declarations) { + inlineClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration) + } + declaration + } + + private fun transformExpressionConsequently(expression: IrExpression) = expression + .transform(multiFieldValueClassLowering, null) + .transform(inlineClassLowering, null) + + private fun transformStatementConsequently(statement: IrStatement) = statement + .transformStatement(multiFieldValueClassLowering) + .transformStatement(inlineClassLowering) + + private fun IrElement.requiresHandling(lowering: JvmValueClassAbstractLowering) = + accept(object : IrElementVisitor { + override fun visitElement(element: IrElement, data: Nothing?): Boolean = false + override fun visitClass(declaration: IrClass, data: Nothing?): Boolean = + lowering.needsToVisitClassNew(declaration) || super.visitClass(declaration, data) + + override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean = + lowering.needsToVisitFunctionReference(expression) || super.visitFunctionReference(expression, data) + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean = + lowering.needsToVisitFunctionAccess(expression) || super.visitFunctionAccess(expression, data) + + override fun visitCall(expression: IrCall, data: Nothing?): Boolean = + lowering.needsToVisitCall(expression) || super.visitCall(expression, data) + + override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean = + lowering.needsToVisitStringConcatenation(expression) || super.visitStringConcatenation(expression, data) + + override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean = + lowering.needsToVisitGetField(expression) || super.visitGetField(expression, data) + + override fun visitSetField(expression: IrSetField, data: Nothing?): Boolean = + lowering.needsToVisitSetField(expression) || super.visitSetField(expression, data) + + override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean = + lowering.needsToVisitGetValue(expression) || super.visitGetValue(expression, data) + + override fun visitSetValue(expression: IrSetValue, data: Nothing?): Boolean = + lowering.needsToVisitSetValue(expression) || super.visitSetValue(expression, data) + + override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean = + lowering.needsToVisitVariable(declaration) || super.visitVariable(declaration, data) + + override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean = + lowering.needsToVisitReturn(expression) || super.visitReturn(expression, data) + }, null) + + override fun visitFunctionReference(expression: IrFunctionReference): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitFunctionReference(expression) + } + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitFunctionAccess(expression) + } + + override fun visitCall(expression: IrCall): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitCall(expression) + } + + override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitStringConcatenation(expression) + } + + override fun visitGetField(expression: IrGetField): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitGetField(expression) + } + + override fun visitSetField(expression: IrSetField): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitSetField(expression) + } + + override fun visitGetValue(expression: IrGetValue): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitGetValue(expression) + } + + override fun visitSetValue(expression: IrSetValue): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitSetValue(expression) + } + + override fun visitVariable(declaration: IrVariable): IrStatement = if (declaration.requiresAnyHandling()) { + transformStatementConsequently(declaration) + } else { + super.visitVariable(declaration) + } + + override fun visitReturn(expression: IrReturn): IrExpression = if (expression.requiresAnyHandling()) { + transformExpressionConsequently(expression) + } else { + super.visitReturn(expression) + } + + override fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement = if (declaration.requiresAnyHandling()) { + transformStatementConsequently(declaration) + } else { + super.visitAnonymousInitializerNew(declaration) + } + + private fun visitStatementContainer(container: IrStatementContainer) = if (container.statements.any { it.requiresAnyHandling() }) { + multiFieldValueClassLowering.visitStatementContainer(container) + inlineClassLowering.visitStatementContainer(container) + } else { + container.statements.replaceAll { it.transformStatement(this) } + } + + override fun visitContainerExpression(expression: IrContainerExpression): IrExpression { + visitStatementContainer(expression) + return expression + } + + override fun visitBlockBody(body: IrBlockBody): IrBody { + visitStatementContainer(body) + return body + } +} \ No newline at end of file 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 3137cf29c7c..16abae1e62f 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 @@ -95,7 +95,7 @@ abstract class MemoizedValueClassAbstractReplacements( annotations = propertySymbol.owner.annotations // In case this property is declared in an object in another file which is not yet lowered, its backing field will // be made static later. We have to handle it here though, because this new property will be saved to the cache - // and reused when lowering the same call in all subsequent files, which would be incorrect if it was unlowered. + // and reused when lowering the same call in all subsequent files, which would be incorrect if it was not lowered. backingField = context.cachedDeclarations.getStaticBackingField(propertySymbol.owner) ?: propertySymbol.owner.backingField } @@ -132,5 +132,5 @@ abstract class MemoizedValueClassAbstractReplacements( function.overriddenSymbols = replaceOverriddenSymbols(function) } - protected abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean + abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean } \ No newline at end of file