Make InitializersLowering a BodyLoweringPass and add a InitializersCleanupLowering

This commit is contained in:
Anton Bannykh
2019-12-22 23:56:35 +03:00
committed by Anton Bannykh
parent 600caaa636
commit 6e96e271ae
5 changed files with 99 additions and 34 deletions
@@ -5,41 +5,64 @@
package org.jetbrains.kotlin.backend.common.lower package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.*
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK") object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) { open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context), BodyLoweringPass {
override fun lower(irClass: IrClass) {
override fun lower(irFile: IrFile) {
runOnFilePostfix(irFile, true)
}
override fun lower(irBody: IrBody, container: IrDeclaration) {
if (container !is IrConstructor) return
val irClass = container.constructedClass
val instanceInitializerStatements = extractInitializers(irClass) { val instanceInitializerStatements = extractInitializers(irClass) {
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic) (it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
} }
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
// Only transform constructors of current class.
override fun visitClassNew(declaration: IrClass) = declaration
override fun visitSimpleFunction(declaration: IrSimpleFunction) = declaration container.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
.deepCopyWithSymbols(container).also {
// Handle declarations, copied from initializers
// Otherwise local classes inside them won't get processed.
// Yes, there are such cases - see testData/codegen/box/properties/complexPropertyInitializer.kt
it.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression = override fun visitConstructor(declaration: IrConstructor) {
IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements) super.visitConstructor(declaration)
.deepCopyWithSymbols(currentScope!!.scope.getLocalDeclarationParent())
declaration.body?.let { lower(it, declaration) }
}
})
}
}
}) })
} }
} }
abstract class InitializersLoweringBase(open val context: CommonBackendContext) : ClassLoweringPass { abstract class InitializersLoweringBase(open val context: CommonBackendContext) {
protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) = protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) =
irClass.declarations.filter(filter).mapNotNull { irClass.declarations.filter(filter).mapNotNull {
when (it) { when (it) {
@@ -47,25 +70,15 @@ abstract class InitializersLoweringBase(open val context: CommonBackendContext)
is IrAnonymousInitializer -> handleAnonymousInitializer(it) is IrAnonymousInitializer -> handleAnonymousInitializer(it)
else -> null else -> null
} }
}.also {
irClass.declarations.removeAll { it is IrAnonymousInitializer && filter(it) }
} }
protected open fun shouldEraseFieldInitializer(irField: IrField): Boolean = irField.correspondingPropertySymbol?.owner?.isConst != true
private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? = private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? =
declaration.initializer?.run { declaration.initializer?.run {
val receiver = if (!declaration.isStatic) // TODO isStaticField val receiver = if (!declaration.isStatic) // TODO isStaticField
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol) IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol)
else else
null null
val value = if (shouldEraseFieldInitializer(declaration)) { IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType)
declaration.initializer = null
expression
} else {
expression.deepCopyWithSymbols()
}
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, value, context.irBuiltIns.unitType)
} }
private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement = private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
@@ -73,3 +86,31 @@ abstract class InitializersLoweringBase(open val context: CommonBackendContext)
IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements) IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements)
} }
} }
// Remove anonymous initializers and set field initializers to `null`
class InitializersCleanupLowering(
val context: CommonBackendContext,
private val shouldEraseFieldInitializer: (IrField) -> Boolean = { it.correspondingPropertySymbol?.owner?.isConst != true }
) : DeclarationTransformer {
override fun lower(irFile: IrFile) {
runPostfix(withLocalDeclarations = true).toFileLoweringPass().lower(irFile)
}
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration is IrAnonymousInitializer) return emptyList()
if (declaration is IrField && declaration.parent is IrClass) {
if (shouldEraseFieldInitializer(declaration)) {
declaration.initializer = null
} else {
declaration.initializer?.let {
declaration.initializer =
IrExpressionBodyImpl(it.startOffset, it.endOffset) { expression = it.expression.deepCopyWithSymbols() }
}
}
}
return null
}
}
@@ -293,6 +293,13 @@ private val initializersLoweringPhase = makeJsModulePhase(
prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase, annotationConstructorLowering) prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase, annotationConstructorLowering)
) )
private val initializersCleanupLoweringPhase = makeJsModulePhase(
::InitializersCleanupLowering,
name = "InitializersCleanupLowering",
description = "Remove non-static anonymous initializers and field init expressions",
prerequisite = setOf(initializersLoweringPhase)
)
private val multipleCatchesLoweringPhase = makeJsModulePhase( private val multipleCatchesLoweringPhase = makeJsModulePhase(
::MultipleCatchesLowering, ::MultipleCatchesLowering,
name = "MultipleCatchesLowering", name = "MultipleCatchesLowering",
@@ -428,6 +435,7 @@ val jsPhases = namedIrModulePhase(
primaryConstructorLoweringPhase then primaryConstructorLoweringPhase then
annotationConstructorLowering then annotationConstructorLowering then
initializersLoweringPhase then initializersLoweringPhase then
initializersCleanupLoweringPhase then
// Common prefix ends // Common prefix ends
enumClassLoweringPhase then enumClassLoweringPhase then
enumUsageLoweringPhase then enumUsageLoweringPhase then
@@ -178,14 +178,21 @@ private val staticInitializersPhase = makeIrFilePhase(
) )
private val initializersPhase = makeIrFilePhase<JvmBackendContext>( private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
{ context -> ::InitializersLowering,
object : InitializersLowering(context) {
override fun shouldEraseFieldInitializer(irField: IrField): Boolean =
irField.constantValue(context) == null
}
},
name = "Initializers", name = "Initializers",
description = "Merge init blocks and field initializers into constructors", description = "Merge init blocks and field initializers into constructors",
// Depends on local class extraction, because otherwise local classes in initializers will be copied into each constructor.
prerequisite = setOf(jvmLocalClassExtractionPhase)
)
private val initializersCleanupPhase = makeIrFilePhase<JvmBackendContext>(
{ context ->
InitializersCleanupLowering(context) {
it.constantValue(context) == null && (!it.isStatic || it.correspondingPropertySymbol?.owner?.isConst != true)
}
},
name = "InitializersCleanup",
description = "Remove non-static anonymous initializers and non-constant non-static field init expressions",
stickyPostconditions = setOf(fun(irFile: IrFile) { stickyPostconditions = setOf(fun(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid { irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
@@ -197,8 +204,7 @@ private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
} }
}) })
}), }),
// Depends on local class extraction, because otherwise local classes in initializers will be copied into each constructor. prerequisite = setOf(initializersPhase)
prerequisite = setOf(jvmLocalClassExtractionPhase)
) )
private val returnableBlocksPhase = makeIrFilePhase( private val returnableBlocksPhase = makeIrFilePhase(
@@ -293,6 +299,7 @@ private val jvmFilePhases =
objectClassPhase then objectClassPhase then
staticInitializersPhase then staticInitializersPhase then
initializersPhase then initializersPhase then
initializersCleanupPhase then
collectionStubMethodLowering then collectionStubMethodLowering then
functionNVarargBridgePhase then functionNVarargBridgePhase then
bridgePhase then bridgePhase then
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.lower package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
@@ -19,7 +20,7 @@ import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class StaticInitializersLowering(override val context: JvmBackendContext) : InitializersLoweringBase(context) { class StaticInitializersLowering(override val context: JvmBackendContext) : InitializersLoweringBase(context), ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
val staticInitializerStatements = extractInitializers(irClass) { val staticInitializerStatements = extractInitializers(irClass) {
// JVM implementations are required to generate initializers for all static fields with ConstantValue, // JVM implementations are required to generate initializers for all static fields with ConstantValue,
@@ -208,6 +208,13 @@ private val initializersLoweringPhase = makeWasmModulePhase(
prerequisite = setOf(primaryConstructorLoweringPhase) prerequisite = setOf(primaryConstructorLoweringPhase)
) )
private val initializersCleanupLoweringPhase = makeWasmModulePhase(
::InitializersCleanupLowering,
name = "InitializersCleanupLowering",
description = "Remove non-static anonymous initializers and field init expressions",
prerequisite = setOf(initializersLoweringPhase)
)
private val excludeDeclarationsFromCodegenPhase = makeCustomWasmModulePhase( private val excludeDeclarationsFromCodegenPhase = makeCustomWasmModulePhase(
{ context, module -> { context, module ->
excludeDeclarationsFromCodegen(context, module) excludeDeclarationsFromCodegen(context, module)
@@ -336,6 +343,7 @@ val wasmPhases = namedIrModulePhase<WasmBackendContext>(
propertiesLoweringPhase then propertiesLoweringPhase then
primaryConstructorLoweringPhase then primaryConstructorLoweringPhase then
initializersLoweringPhase then initializersLoweringPhase then
initializersCleanupLoweringPhase then
// Common prefix ends // Common prefix ends
builtInsLoweringPhase then builtInsLoweringPhase then