From 3246b0a6bdc786ca9cb3196335950cb6ba80eff7 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 23 Aug 2023 21:53:03 +0200 Subject: [PATCH] JVM IR: inherit some lowerings from ClassLoweringPass This slightly simplifies code, but has no other immediate benefits. In the future though, we may end up optimizing all ClassLoweringPass JVM IR phases by making them traverse only one list of all classes in the module, instead of traversing the whole IR tree each time. --- .../backend/jvm/lower/AnnotationLowering.kt | 19 ++++-------- .../backend/jvm/lower/BridgeLowering.kt | 30 +++++++------------ ...nheritedDefaultMethodsOnClassesLowering.kt | 21 ++++++------- .../backend/jvm/lower/ObjectClassLowering.kt | 24 +++++---------- 4 files changed, 35 insertions(+), 59 deletions(-) diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AnnotationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AnnotationLowering.kt index 32436d16b6a..2334995a19d 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AnnotationLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/AnnotationLowering.kt @@ -5,16 +5,12 @@ package org.jetbrains.kotlin.backend.jvm.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.util.isAnnotationClass -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid internal val annotationPhase = makeIrFilePhase( { AnnotationLowering() }, @@ -22,13 +18,10 @@ internal val annotationPhase = makeIrFilePhase( description = "Remove constructors of annotation classes" ) -private class AnnotationLowering : FileLoweringPass, IrElementTransformerVoid() { - override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this) - - override fun visitClass(declaration: IrClass): IrStatement = - declaration.transformPostfix { - if (isAnnotationClass) { - declarations.removeIf { it is IrConstructor } - } +private class AnnotationLowering : ClassLoweringPass { + override fun lower(irClass: IrClass) { + if (irClass.isAnnotationClass) { + irClass.declarations.removeIf { it is IrConstructor } } + } } 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 798359c1c17..06f9feb33e7 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 @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.backend.jvm.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.lower.SpecialMethodWithDefaultInfo import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irNot @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.declarations.* @@ -30,7 +29,6 @@ import org.jetbrains.kotlin.ir.types.isNullable import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.org.objectweb.asm.Type @@ -118,7 +116,7 @@ internal val bridgePhase = makeIrFilePhase( prerequisite = setOf(jvmValueClassPhase, inheritedDefaultMethodsOnClassesPhase) ) -internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() { +internal class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass { // Represents a synthetic bridge to `overridden` with a precomputed signature private class Bridge( val overridden: IrSimpleFunction, @@ -126,27 +124,21 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass val overriddenSymbols: MutableList = mutableListOf() ) - override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid() - } + override fun lower(irClass: IrClass) { + // Bridges in DefaultImpls classes are handled in InterfaceLowering. + if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS || irClass.isAnnotationClass) return - override fun visitClass(declaration: IrClass): IrStatement { - // Bridges in DefaultImpl classes are handled in InterfaceLowering. - if (declaration.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS || declaration.isAnnotationClass) - return super.visitClass(declaration) + val bridgeTargets = irClass.functions.filterTo(SmartList()) { it.isPotentialBridgeTarget() } + if (bridgeTargets.isEmpty()) return - val bridgeTargets = declaration.functions.filterTo(SmartList()) { it.isPotentialBridgeTarget() } - if (bridgeTargets.isEmpty()) - return super.visitClass(declaration) + bridgeTargets.forEach { createBridges(irClass, it) } - bridgeTargets.forEach { createBridges(declaration, it) } - - if (declaration.isSingleFieldValueClass) { + if (irClass.isSingleFieldValueClass) { // Inline class (implementing 'MutableCollection', where T is Int or an inline class mapped to Int) // can contain a static replacement for a function 'remove', which forces value parameter boxing // in order to avoid signature clash with 'remove(int)' method in 'java.util.List'. // We should rewrite this static replacement as well ('remove' function itself is handled during special bridge processing). - val remove = declaration.functions.find { + val remove = irClass.functions.find { val original = context.inlineClassReplacements.originalFunctionForStaticReplacement[it] original != null && context.defaultMethodSignatureMapper.shouldBoxSingleValueParameterForSpecialCaseOfRemove(original) } @@ -156,8 +148,6 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass } } } - - return super.visitClass(declaration) } private fun IrSimpleFunction.isPotentialBridgeTarget(): Boolean { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt index 3a2b93c5894..c04256ad9cc 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt @@ -28,7 +28,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.expressions.putArgument import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid internal val inheritedDefaultMethodsOnClassesPhase = makeIrFilePhase( ::InheritedDefaultMethodsOnClassesLowering, @@ -123,25 +125,24 @@ internal val replaceDefaultImplsOverriddenSymbolsPhase = makeIrFilePhase( description = "Replace overridden symbols for methods inherited from interfaces to classes" ) -private class ReplaceDefaultImplsOverriddenSymbols(private val context: JvmBackendContext) : FileLoweringPass, IrElementVisitorVoid { - override fun lower(irFile: IrFile) { - irFile.acceptVoid(this) - } - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) +private class ReplaceDefaultImplsOverriddenSymbols(private val context: JvmBackendContext) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + for (declaration in irClass.declarations) { + if (declaration is IrSimpleFunction) { + visitSimpleFunction(declaration) + } + } } // Functions introduced by InheritedDefaultMethodsOnClassesLowering may be inherited lower in the hierarchy. // Here we use the same logic as the delegation itself (`getTargetForRedirection`) to determine // if the overridden symbol has been, or will be, replaced and patch it accordingly. - override fun visitSimpleFunction(declaration: IrSimpleFunction) { + fun visitSimpleFunction(declaration: IrSimpleFunction) { declaration.overriddenSymbols = declaration.overriddenSymbols.map { symbol -> if (symbol.owner.findInterfaceImplementation(context.config.jvmDefaultMode) != null) context.cachedDeclarations.getDefaultImplsRedirection(symbol.owner).symbol else symbol } - super.visitSimpleFunction(declaration) } } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt index 5f2b38ec88f..ee4eeea9ade 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt @@ -5,15 +5,13 @@ 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.ClassLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irExprBody import org.jetbrains.kotlin.ir.builders.irGetField @@ -31,23 +29,17 @@ internal val objectClassPhase = makeIrFilePhase( description = "Handle object classes" ) -private class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { - - private var pendingTransformations = mutableListOf>() +private class ObjectClassLowering(val context: JvmBackendContext) : ClassLoweringPass { + private val pendingTransformations = mutableListOf>() override fun lower(irFile: IrFile) { - irFile.accept(this, null) - - pendingTransformations.forEach { it() } + super.lower(irFile) + for (transformation in pendingTransformations) { + transformation.invoke() + } } - override fun visitClassNew(declaration: IrClass): IrStatement { - process(declaration) - return super.visitClassNew(declaration) - } - - - private fun process(irClass: IrClass) { + override fun lower(irClass: IrClass) { if (!irClass.isObject) return val publicInstanceField = context.cachedDeclarations.getFieldForObjectInstance(irClass)