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.
This commit is contained in:
Alexander Udalov
2023-08-23 21:53:03 +02:00
committed by Space Team
parent 073df585c4
commit 3246b0a6bd
4 changed files with 35 additions and 59 deletions
@@ -5,16 +5,12 @@
package org.jetbrains.kotlin.backend.jvm.lower 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.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext 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.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor 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.util.isAnnotationClass
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal val annotationPhase = makeIrFilePhase<JvmBackendContext>( internal val annotationPhase = makeIrFilePhase<JvmBackendContext>(
{ AnnotationLowering() }, { AnnotationLowering() },
@@ -22,13 +18,10 @@ internal val annotationPhase = makeIrFilePhase<JvmBackendContext>(
description = "Remove constructors of annotation classes" description = "Remove constructors of annotation classes"
) )
private class AnnotationLowering : FileLoweringPass, IrElementTransformerVoid() { private class AnnotationLowering : ClassLoweringPass {
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this) override fun lower(irClass: IrClass) {
if (irClass.isAnnotationClass) {
override fun visitClass(declaration: IrClass): IrStatement = irClass.declarations.removeIf { it is IrConstructor }
declaration.transformPostfix {
if (isAnnotationClass) {
declarations.removeIf { it is IrConstructor }
}
} }
}
} }
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.lower 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.SpecialMethodWithDefaultInfo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irNot 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.codegen.AsmUtil
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.declarations.* 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.isPrimitiveType
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -118,7 +116,7 @@ internal val bridgePhase = makeIrFilePhase(
prerequisite = setOf(jvmValueClassPhase, inheritedDefaultMethodsOnClassesPhase) 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 // Represents a synthetic bridge to `overridden` with a precomputed signature
private class Bridge( private class Bridge(
val overridden: IrSimpleFunction, val overridden: IrSimpleFunction,
@@ -126,27 +124,21 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
val overriddenSymbols: MutableList<IrSimpleFunctionSymbol> = mutableListOf() val overriddenSymbols: MutableList<IrSimpleFunctionSymbol> = mutableListOf()
) )
override fun lower(irFile: IrFile) { override fun lower(irClass: IrClass) {
irFile.transformChildrenVoid() // Bridges in DefaultImpls classes are handled in InterfaceLowering.
} if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS || irClass.isAnnotationClass) return
override fun visitClass(declaration: IrClass): IrStatement { val bridgeTargets = irClass.functions.filterTo(SmartList()) { it.isPotentialBridgeTarget() }
// Bridges in DefaultImpl classes are handled in InterfaceLowering. if (bridgeTargets.isEmpty()) return
if (declaration.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS || declaration.isAnnotationClass)
return super.visitClass(declaration)
val bridgeTargets = declaration.functions.filterTo(SmartList()) { it.isPotentialBridgeTarget() } bridgeTargets.forEach { createBridges(irClass, it) }
if (bridgeTargets.isEmpty())
return super.visitClass(declaration)
bridgeTargets.forEach { createBridges(declaration, it) } if (irClass.isSingleFieldValueClass) {
if (declaration.isSingleFieldValueClass) {
// Inline class (implementing 'MutableCollection<T>', where T is Int or an inline class mapped to Int) // Inline class (implementing 'MutableCollection<T>', 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 // 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'. // 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). // 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] val original = context.inlineClassReplacements.originalFunctionForStaticReplacement[it]
original != null && context.defaultMethodSignatureMapper.shouldBoxSingleValueParameterForSpecialCaseOfRemove(original) 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 { private fun IrSimpleFunction.isPotentialBridgeTarget(): Boolean {
@@ -28,7 +28,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.expressions.putArgument import org.jetbrains.kotlin.ir.expressions.putArgument
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.* 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( internal val inheritedDefaultMethodsOnClassesPhase = makeIrFilePhase(
::InheritedDefaultMethodsOnClassesLowering, ::InheritedDefaultMethodsOnClassesLowering,
@@ -123,25 +125,24 @@ internal val replaceDefaultImplsOverriddenSymbolsPhase = makeIrFilePhase(
description = "Replace overridden symbols for methods inherited from interfaces to classes" description = "Replace overridden symbols for methods inherited from interfaces to classes"
) )
private class ReplaceDefaultImplsOverriddenSymbols(private val context: JvmBackendContext) : FileLoweringPass, IrElementVisitorVoid { private class ReplaceDefaultImplsOverriddenSymbols(private val context: JvmBackendContext) : ClassLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irClass: IrClass) {
irFile.acceptVoid(this) for (declaration in irClass.declarations) {
} if (declaration is IrSimpleFunction) {
visitSimpleFunction(declaration)
override fun visitElement(element: IrElement) { }
element.acceptChildrenVoid(this) }
} }
// Functions introduced by InheritedDefaultMethodsOnClassesLowering may be inherited lower in the hierarchy. // Functions introduced by InheritedDefaultMethodsOnClassesLowering may be inherited lower in the hierarchy.
// Here we use the same logic as the delegation itself (`getTargetForRedirection`) to determine // 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. // 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 -> declaration.overriddenSymbols = declaration.overriddenSymbols.map { symbol ->
if (symbol.owner.findInterfaceImplementation(context.config.jvmDefaultMode) != null) if (symbol.owner.findInterfaceImplementation(context.config.jvmDefaultMode) != null)
context.cachedDeclarations.getDefaultImplsRedirection(symbol.owner).symbol context.cachedDeclarations.getDefaultImplsRedirection(symbol.owner).symbol
else symbol else symbol
} }
super.visitSimpleFunction(declaration)
} }
} }
@@ -5,15 +5,13 @@
package org.jetbrains.kotlin.backend.jvm.lower 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.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities 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.irCall
import org.jetbrains.kotlin.ir.builders.irExprBody import org.jetbrains.kotlin.ir.builders.irExprBody
import org.jetbrains.kotlin.ir.builders.irGetField import org.jetbrains.kotlin.ir.builders.irGetField
@@ -31,23 +29,17 @@ internal val objectClassPhase = makeIrFilePhase(
description = "Handle object classes" description = "Handle object classes"
) )
private class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { private class ObjectClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
private val pendingTransformations = mutableListOf<Function0<Unit>>()
private var pendingTransformations = mutableListOf<Function0<Unit>>()
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.accept(this, null) super.lower(irFile)
for (transformation in pendingTransformations) {
pendingTransformations.forEach { it() } transformation.invoke()
}
} }
override fun visitClassNew(declaration: IrClass): IrStatement { override fun lower(irClass: IrClass) {
process(declaration)
return super.visitClassNew(declaration)
}
private fun process(irClass: IrClass) {
if (!irClass.isObject) return if (!irClass.isObject) return
val publicInstanceField = context.cachedDeclarations.getFieldForObjectInstance(irClass) val publicInstanceField = context.cachedDeclarations.getFieldForObjectInstance(irClass)