diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt index bc66b6ff837..3411f25f569 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt @@ -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 = 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) { + 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) { - 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) { - // 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("") - - 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) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt index b88ef715352..b3c843935a5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/DeclarationOrigins.kt @@ -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") -} \ No newline at end of file +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 6dd58663940..e9ed4217a17 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 152813a7682..8388bea7023 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -173,8 +173,14 @@ private val innerClassesPhase = makeIrFilePhase( prerequisite = setOf(localDeclarationsPhase) ) -private val initializersPhase = makeIrFilePhase( - { 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 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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt index 14a6b6ad9e3..1b6b1b6cf9c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt new file mode 100644 index 00000000000..c6ee9918e08 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/StaticInitializersLowering.kt @@ -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 = + // 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) { + // 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("") + } +} diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 02efa614790..2f463ec61a6 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -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)