IR: extract StaticInitializersLowering out of InitializersLowering

And use it in JVM backend only. Also remove unneeded
`patchDeclarationParents` call.
This commit is contained in:
Alexander Udalov
2019-10-30 19:06:30 +01:00
parent 098561dd5f
commit 9a55f418fa
7 changed files with 121 additions and 95 deletions
@@ -7,67 +7,53 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
class InitializersLowering(
val context: CommonBackendContext,
private val declarationOrigin: IrDeclarationOrigin,
private val clinitNeeded: Boolean
) : ClassLoweringPass {
open class InitializersLowering(
context: CommonBackendContext
) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) {
val instanceInitializerStatements = handleNonStatics(irClass)
val nonStaticDeclarations = getDeclarationsWithNonStaticInitializers(irClass)
val instanceInitializerStatements = nonStaticDeclarations.mapNotNull { handleDeclaration(irClass, it) }
transformInstanceInitializerCallsInConstructors(irClass, instanceInitializerStatements)
val staticInitializerStatements = handleStatics(irClass)
if (clinitNeeded && staticInitializerStatements.isNotEmpty())
createStaticInitializationMethod(irClass, staticInitializerStatements)
irClass.declarations.removeAll { it is IrAnonymousInitializer }
irClass.patchDeclarationParents(irClass.parent)
val anonymousInitializers = nonStaticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer }
irClass.declarations.removeAll(anonymousInitializers)
}
private fun handleNonStatics(irClass: IrClass) =
private fun getDeclarationsWithNonStaticInitializers(irClass: IrClass): List<IrDeclaration> =
irClass.declarations.filter {
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
}.mapNotNull { handleDeclaration(irClass, it) }
}
private fun handleStatics(irClass: IrClass) =
// Hardcoded order of initializers
(irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE } +
irClass.declarations.filter {
(it is IrField && it.isStatic && it.origin !in listOf(
IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY,
IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES,
IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
)) || (it is IrAnonymousInitializer && it.isStatic)
})
.mapNotNull { handleDeclaration(irClass, it) }
private fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List<IrStatement>) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val copiedBlock =
IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements)
.copy(irClass) as IrBlock
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements)
}
})
}
}
private fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when (declaration) {
abstract class InitializersLoweringBase(val context: CommonBackendContext) : ClassLoweringPass {
protected fun handleDeclaration(irClass: IrClass, declaration: IrDeclaration): IrStatement? = when (declaration) {
is IrField -> handleField(irClass, declaration)
is IrAnonymousInitializer -> handleAnonymousInitializer(declaration)
else -> null
@@ -100,51 +86,5 @@ class InitializersLowering(
declaration.body.statements
)
private fun transformInstanceInitializerCallsInConstructors(irClass: IrClass, instanceInitializerStatements: List<IrStatement>) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val copiedBlock =
IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements).copy(
irClass
) as IrBlock
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements)
}
})
}
private fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List<IrStatement>) {
// TODO: mark as synthesized
val staticInitializerDescriptor = WrappedSimpleFunctionDescriptor()
val staticInitializer = IrFunctionImpl(
irClass.startOffset,
irClass.endOffset,
declarationOrigin,
IrSimpleFunctionSymbolImpl(staticInitializerDescriptor),
clinitName,
Visibilities.PUBLIC,
Modality.FINAL,
returnType = context.irBuiltIns.unitType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
isExpect = false,
isFakeOverride = false
).apply {
staticInitializerDescriptor.bind(this)
body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
staticInitializerStatements.map { it.copy(irClass) })
accept(SetDeclarationsParentVisitor, this)
// Should come after SetDeclarationParentVisitor, because it sets staticInitializer's own parent to itself.
parent = irClass
}
irClass.declarations.add(staticInitializer)
}
companion object {
val clinitName = Name.special("<clinit>")
private fun IrStatement.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration)
private fun IrExpression.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration)
}
protected fun IrStatement.copy(containingDeclaration: IrDeclarationParent): IrStatement = deepCopyWithSymbols(containingDeclaration)
}
@@ -10,9 +10,8 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS")
object JS_CLOSURE_BOX_CLASS_DECLARATION : IrDeclarationOriginImpl("JS_CLOSURE_BOX_CLASS_DECLARATION")
object BRIDGE_TO_EXTERNAL_FUNCTION : IrDeclarationOriginImpl("BRIDGE_TO_EXTERNAL_FUNCTION")
}
}
@@ -258,8 +258,8 @@ private val primaryConstructorLoweringPhase = makeJsModulePhase(
prerequisite = setOf(enumClassConstructorLoweringPhase)
)
private val initializersLoweringPhase = makeCustomJsModulePhase(
{ context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
private val initializersLoweringPhase = makeJsModulePhase(
::InitializersLowering,
name = "InitializersLowering",
description = "Merge init block and field initializers into [primary] constructor",
prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase)
@@ -173,8 +173,14 @@ private val innerClassesPhase = makeIrFilePhase(
prerequisite = setOf(localDeclarationsPhase)
)
private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
{ context -> InitializersLowering(context, JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, clinitNeeded = true) },
private val staticInitializersPhase = makeIrFilePhase(
::StaticInitializersLowering,
name = "StaticInitializers",
description = "Move code from object init blocks and static field initializers to a new <clinit> function"
)
private val initializersPhase = makeIrFilePhase(
::InitializersLowering,
name = "Initializers",
description = "Merge init blocks and field initializers into constructors",
stickyPostconditions = setOf(fun(irFile: IrFile) {
@@ -276,6 +282,7 @@ private val jvmFilePhases =
enumClassPhase then
objectClassPhase then
staticInitializersPhase then
initializersPhase then
collectionStubMethodLowering then
functionNVarargBridgePhase then
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.lower.InitializersLowering
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
@@ -167,7 +166,7 @@ private fun IrField.shouldMoveToFacade(): Boolean {
private fun IrFunction.createMultifileDelegateIfNeeded(context: JvmBackendContext, facadeClass: IrClass): IrFunction? {
if (Visibilities.isPrivate(visibility) ||
name == InitializersLowering.clinitName ||
name == StaticInitializersLowering.clinitName ||
origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
) return null
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2019 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.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.SetDeclarationsParentVisitor
import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.name.Name
class StaticInitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
override fun lower(irClass: IrClass) {
val staticDeclarations = getDeclarationsWithStaticInitializers(irClass)
val staticInitializerStatements = staticDeclarations.mapNotNull { handleDeclaration(irClass, it) }
if (staticInitializerStatements.isNotEmpty()) {
createStaticInitializationMethod(irClass, staticInitializerStatements)
val anonymousInitializers = staticDeclarations.filterTo(hashSetOf()) { it is IrAnonymousInitializer }
irClass.declarations.removeAll(anonymousInitializers)
}
}
private fun getDeclarationsWithStaticInitializers(irClass: IrClass): List<IrDeclaration> =
// Hardcoded order of initializers
(irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES } +
irClass.declarations.filter { it is IrField && it.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE } +
irClass.declarations.filter {
(it is IrField && it.isStatic && it.origin !in listOf(
IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY,
IrDeclarationOrigin.FIELD_FOR_ENUM_VALUES,
IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
)) || (it is IrAnonymousInitializer && it.isStatic)
})
private fun createStaticInitializationMethod(irClass: IrClass, staticInitializerStatements: List<IrStatement>) {
// TODO: mark as synthesized
val staticInitializerDescriptor = WrappedSimpleFunctionDescriptor()
val staticInitializer = IrFunctionImpl(
irClass.startOffset,
irClass.endOffset,
JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER,
IrSimpleFunctionSymbolImpl(staticInitializerDescriptor),
clinitName,
Visibilities.PUBLIC,
Modality.FINAL,
returnType = context.irBuiltIns.unitType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
isExpect = false,
isFakeOverride = false
).apply {
staticInitializerDescriptor.bind(this)
body = IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
staticInitializerStatements.map { it.copy(irClass) })
accept(SetDeclarationsParentVisitor, this)
// Should come after SetDeclarationParentVisitor, because it sets staticInitializer's own parent to itself.
parent = irClass
}
irClass.declarations.add(staticInitializer)
}
companion object {
val clinitName = Name.special("<clinit>")
}
}
@@ -5,14 +5,16 @@
package org.jetbrains.kotlin.backend.wasm
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.wasm.lower.BuiltInsLowering
import org.jetbrains.kotlin.backend.wasm.lower.WasmBlockDecomposerLowering
import org.jetbrains.kotlin.backend.wasm.lower.excludeDeclarationsFromCodegen
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.lower.*
import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -199,8 +201,8 @@ private val primaryConstructorLoweringPhase = makeWasmModulePhase(
description = "Creates primary constructor if it doesn't exist"
)
private val initializersLoweringPhase = makeCustomWasmModulePhase(
{ context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
private val initializersLoweringPhase = makeWasmModulePhase(
::InitializersLowering,
name = "InitializersLowering",
description = "Merge init block and field initializers into [primary] constructor",
prerequisite = setOf(primaryConstructorLoweringPhase)