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 c76db464522..58858d593d0 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 @@ -109,6 +109,16 @@ class ModuleLowering( override val modulePhase: NamedCompilerPhase> ) : Lowering(name) +class FileLowering( + name: String, + description: String, + prerequisite: Set> = emptySet(), + private val factory: (JsIrBackendContext) -> FileLoweringPass +) : Lowering(name) { + override val modulePhase: NamedCompilerPhase> = + makeJsModulePhase(factory, name, description, prerequisite) +} + private fun makeDeclarationTransformerPhase( lowering: (JsIrBackendContext) -> DeclarationTransformer, name: String, @@ -123,6 +133,13 @@ private fun makeBodyLoweringPhase( prerequisite: Set = emptySet() ) = BodyLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering) +private fun makeFileLoweringPhase( + lowering: (JsIrBackendContext) -> FileLoweringPass, + name: String, + description: String, + prerequisite: Set = emptySet() +) = FileLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering) + fun NamedCompilerPhase>.toModuleLowering() = ModuleLowering(this.name, this) private val validateIrBeforeLowering = makeCustomJsModulePhase( @@ -352,6 +369,12 @@ private val forLoopsLoweringPhase = makeBodyLoweringPhase( description = "[Optimization] For loops lowering" ) +private val propertyLazyInitLoweringPhase = makeFileLoweringPhase( + ::PropertyLazyInitLowering, + name = "PropertyLazyInitLowering", + description = "Make property init as lazy" +) + private val propertyAccessorInlinerLoweringPhase = makeBodyLoweringPhase( ::PropertyAccessorInlineLowering, name = "PropertyAccessorInlineLowering", @@ -727,6 +750,7 @@ val loweringList = listOf( rangeContainsLoweringPhase, forLoopsLoweringPhase, primitiveCompanionLoweringPhase, + propertyLazyInitLoweringPhase, propertyAccessorInlinerLoweringPhase, foldConstantLoweringPhase, privateMembersLoweringPhase, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt new file mode 100644 index 00000000000..19a341cce8d --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PropertyLazyInitLowering.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2020 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.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.builders.declarations.addFunction +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrSetField +import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl +import org.jetbrains.kotlin.ir.util.kotlinFqName +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name + +class PropertyLazyInitLowering(private val context: JsIrBackendContext) : FileLoweringPass { + private val irBuiltIns + get() = context.irBuiltIns + + override fun lower(irFile: IrFile) { + val initializers = PropertyInitializerMover(context).process(irFile) + val irFactory = context.irFactory + if (initializers.isNotEmpty()) { + irFactory.addFunction(irFile) { + name = Name.identifier("init properties ${irFile.kotlinFqName}") + returnType = irBuiltIns.unitType + origin = JsIrBuilder.SYNTHESIZED_DECLARATION + }.apply { + body = irFactory.createBlockBody( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + initializers + .map { (field, expression) -> + createIrSetField(field, expression) + } + ) + } + } + } + + private fun createIrSetField(field: IrField, expression: IrExpression): IrSetField { + return IrSetFieldImpl( + field.startOffset, + field.endOffset, + field.symbol, + null, + expression, + expression.type + ) + } +} + +private class PropertyInitializerMover( + private val context: JsIrBackendContext +) : IrElementTransformerVoid() { + + private val fieldToInitializers = mutableListOf>() + + fun process(irFile: IrFile): List> { + irFile.transformChildrenVoid(this) + return fieldToInitializers + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement { + declaration.correspondingPropertySymbol + ?.owner + ?.takeIf { !it.isConst } + ?.takeIf { !it.isDelegated } + ?.backingField + ?.takeIf { it.initializer != null } + ?.let { field -> + fieldToInitializers.add(field to field.initializer!!.expression) + } + + fieldToInitializers.forEach { it.first.initializer = null } + + return super.visitSimpleFunction(declaration) + } + + override fun visitFieldAccess(expression: IrFieldAccessExpression): IrExpression { + return super.visitFieldAccess(expression) + } + + override fun visitField(declaration: IrField): IrStatement { + return super.visitField(declaration) + } + + override fun visitBody(body: IrBody): IrBody { + return super.visitBody(body) + } +} \ No newline at end of file