From 8477f79d58825014ccc47d8b24bae379ef6fb32b Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Mon, 19 Mar 2018 15:48:31 +0300 Subject: [PATCH] Froze enums on creation + tests --- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 3 ++ .../backend/konan/lower/EnumClassLowering.kt | 49 ++++++++++++------- backend.native/tests/build.gradle | 10 ++++ backend.native/tests/codegen/enum/isFrozen.kt | 13 +++++ backend.native/tests/codegen/enum/loop.kt | 15 ++++++ 5 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 backend.native/tests/codegen/enum/isFrozen.kt create mode 100644 backend.native/tests/codegen/enum/loop.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 46faebdd3c1..12af4d91a58 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -251,6 +251,9 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym val initInstance = symbolTable.referenceSimpleFunction( context.getInternalFunctions("initInstance").single()) + val freeze = symbolTable.referenceSimpleFunction( + builtInsPackage("konan", "worker").getContributedFunctions(Name.identifier("freeze"), NoLookupLocation.FROM_BACKEND).single()) + val getContinuation = symbolTable.referenceSimpleFunction( context.getInternalFunctions("getContinuation").single()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt index 4b835d0051d..4dc337a4dbc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/EnumClassLowering.kt @@ -27,15 +27,19 @@ import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression import org.jetbrains.kotlin.backend.common.ir.createSimpleDelegatingConstructorDescriptor +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid @@ -44,6 +48,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance internal class EnumSyntheticFunctionsBuilder(val context: Context) { fun buildValuesExpression(startOffset: Int, endOffset: Int, @@ -367,29 +372,37 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass { private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") } + private val genericFreezeSymbol = context.ir.symbols.freeze + private val arrayType = context.builtIns.getArrayType(Variance.INVARIANT, irClass.defaultType) + private fun createValuesPropertyInitializer(enumEntries: List): IrAnonymousInitializerImpl { val startOffset = irClass.startOffset val endOffset = irClass.endOffset - val statements = enumEntries - .sortedBy { it.descriptor.name } - .withIndex() - .map { - val instances = IrGetFieldImpl(startOffset, endOffset, - loweredEnum.valuesField.symbol, IrGetValueImpl(startOffset, endOffset, loweredEnum.implObject.thisReceiver!!.symbol)) - val instance = IrCallImpl(startOffset, endOffset, arrayGetSymbol).apply { - dispatchReceiver = instances - putValueArgument(0, IrConstImpl(startOffset, endOffset, context.builtIns.intType, IrConstKind.Int, it.index)) - } - val initializer = it.value.initializerExpression!! as IrCall - IrCallImpl(startOffset, endOffset, initInstanceSymbol).apply { - putValueArgument(0, instance) - putValueArgument(1, initializer) - } + val symbol = IrAnonymousInitializerSymbolImpl(loweredEnum.implObject.descriptor) + val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) + return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, symbol).apply { + body = irBuilder.irBlockBody(irClass) { + val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!.symbol), loweredEnum.valuesField.symbol)) + enumEntries + .sortedBy { it.descriptor.name } + .withIndex() + .forEach { + val instance = irCall(arrayGetSymbol).apply { + dispatchReceiver = irGet(instances.symbol) + putValueArgument(0, irInt(it.index)) + } + val initializer = it.value.initializerExpression!! as IrCall + +irCall(initInstanceSymbol).apply { + putValueArgument(0, instance) + putValueArgument(1, initializer) + } + } + +irCall(genericFreezeSymbol, listOf(arrayType)).apply { + extensionReceiver = irGet(instances.symbol) } - return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, - loweredEnum.implObject.descriptor, IrBlockBodyImpl(startOffset, endOffset, statements) - ) + } + } } private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody { diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 67ae8e9a155..78891b747e8 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -704,6 +704,16 @@ task enum_nested(type: RunKonanTest) { source = "codegen/enum/nested.kt" } +task enum_isFrozen(type: RunKonanTest) { + goldValue = "true\n" + source = "codegen/enum/isFrozen.kt" +} + +task enum_loop(type: RunKonanTest) { + goldValue = "Z\nZ\n" + source = "codegen/enum/loop.kt" +} + task mangling(type: LinkKonanTest) { goldValue = "Int direct [1, 2, 3, 4]\n" + diff --git a/backend.native/tests/codegen/enum/isFrozen.kt b/backend.native/tests/codegen/enum/isFrozen.kt new file mode 100644 index 00000000000..19546db9558 --- /dev/null +++ b/backend.native/tests/codegen/enum/isFrozen.kt @@ -0,0 +1,13 @@ +package codegen.enum.isFrozen + +import kotlin.test.* +import konan.worker.* + +enum class Zzz(val zzz: String) { + Z1("z1"), + Z2("z2") +} + +@Test fun runTest() { + println(Zzz.Z1.isFrozen) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/enum/loop.kt b/backend.native/tests/codegen/enum/loop.kt new file mode 100644 index 00000000000..2e6006dfdfb --- /dev/null +++ b/backend.native/tests/codegen/enum/loop.kt @@ -0,0 +1,15 @@ +package codegen.enum.loop + +import kotlin.test.* + +enum class Zzz { + Z { + init { + println(Z.name) + } + } +} + +@Test fun runTest() { + println(Zzz.Z) +} \ No newline at end of file