Make InitializersLowering a BodyLoweringPass and add a InitializersCleanupLowering
This commit is contained in:
committed by
Anton Bannykh
parent
600caaa636
commit
6e96e271ae
+66
-25
@@ -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
|
||||||
|
|||||||
+2
-1
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user