From cd55e6b1e5b701820780e09ff2b683ca0b70c835 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 22 May 2019 12:57:11 +0300 Subject: [PATCH] [JS IR BE] Use static fields instead of variables in enum lowering --- .../ir/backend/js/lower/EnumClassLowering.kt | 43 +++++++++++-------- .../backend/js/lower/StaticMembersLowering.kt | 7 ++- .../kotlin/ir/builders/ExpressionHelpers.kt | 2 +- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 225b619456b..8797a0b08de 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -19,6 +19,7 @@ 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.* +import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl @@ -36,6 +37,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name import java.util.* class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass { @@ -412,17 +414,20 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: } private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry -> - val type = enumEntry.getType(irClass).makeNullable() - val name = "${enumName}_${enumEntry.name.identifier}_instance" - val result = builder.run { - scope.createTmpVariable(irImplicitCast(irNull(), type), name) + val result = buildField { + name = Name.identifier("${enumName}_${enumEntry.name.identifier}_instance") + type = enumEntry.getType(irClass).makeNullable() + isStatic = true + }.apply { + parent = irClass + initializer = builder.run { irExprBody(irImplicitCast(irNull(), type)) } } enumEntry.correspondingClass?.constructors?.forEach { // Initialize entry instance at the beginning of constructor so it can be used inside constructor body (it.body as? IrBlockBody)?.apply { statements.add(0, context.createIrBuilder(it.symbol).run { - irSetVar(result.symbol, irGet(enumEntry.correspondingClass!!.thisReceiver!!)) + irSetField(null, result, irGet(enumEntry.correspondingClass!!.thisReceiver!!)) }) } } @@ -449,37 +454,39 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: private fun createGetEntryInstanceFuns( initEntryInstancesFun: IrSimpleFunction, - entryInstances: List + entryInstances: List ) = enumEntries.mapIndexed { index, enumEntry -> context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) { buildFunction(createEntryAccessorName(enumName, enumEntry), enumEntry.getType(irClass)) }.apply { body = context.createIrBuilder(symbol).irBlockBody(this) { +irCall(initEntryInstancesFun) - +irReturn(irGet(entryInstances[index])) + +irReturn(irGetField(null, entryInstances[index])) } } } private fun createInitEntryInstancesFun( - entryInstancesInitializedVar: IrVariable, - entryInstances: List + entryInstancesInitializedField: IrField, + entryInstances: List ) = buildFunction("${enumName}_initEntries") { - +irIfThen(irGet(entryInstancesInitializedVar), irReturnUnit()) - +irSetVar(entryInstancesInitializedVar.symbol, irBoolean(true)) - for ((entry, instanceVar) in enumEntries.zip(entryInstances)) { - +irSetVar(instanceVar.symbol, entry.initializerExpression!!) + +irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit()) + +irSetField(null, entryInstancesInitializedField, irBoolean(true)) + for ((entry, instanceField) in enumEntries.zip(entryInstances)) { + +irSetField(null, instanceField, entry.initializerExpression!!) } }.also { // entry.initializerExpression can have local declarations it.acceptVoid(PatchDeclarationParentsVisitor(irClass)) } - private fun createEntryInstancesInitializedVar(): IrVariable { - return builder.scope.createTemporaryVariable( - builder.irBoolean(false), - "${enumName}_entriesInitialized" - ) + private fun createEntryInstancesInitializedVar(): IrField = buildField { + name = Name.identifier("${enumName}_entriesInitialized") + type = context.irBuiltIns.booleanType + isStatic = true + }.apply { + parent = irClass + initializer = builder.run { irExprBody(irBoolean(false)) } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt index 46575ecca06..8c8a819741f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/StaticMembersLowering.kt @@ -38,11 +38,10 @@ class StaticMembersLowering(val context: JsIrBackendContext) : FileLoweringPass super.visitSimpleFunction(declaration) } - override fun visitVariable(declaration: IrVariable) { - // TODO: Don't generate variables inside classes - if (declaration.parent is IrClass) + override fun visitField(declaration: IrField) { + if (declaration.parent is IrClass && declaration.isStatic) staticDeclarationsInClasses.add(declaration) - super.visitVariable(declaration) + super.visitField(declaration) } }) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt index 3099b20ff7d..aa69094d3e0 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt @@ -170,7 +170,7 @@ fun IrBuilderWithScope.irGetField(receiver: IrExpression?, field: IrField) = IrGetFieldImpl(startOffset, endOffset, field.symbol, field.type, receiver) fun IrBuilderWithScope.irSetField(receiver: IrExpression?, field: IrField, value: IrExpression) = - IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, field.type) + IrSetFieldImpl(startOffset, endOffset, field.symbol, receiver, value, context.irBuiltIns.unitType) fun IrBuilderWithScope.irGetObjectValue(type: IrType, classSymbol: IrClassSymbol) = IrGetObjectValueImpl(startOffset, endOffset, type, classSymbol)