From f42336932794f87a5b49aaf8229f66124b1f26cb Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 28 Sep 2016 15:44:16 +0300 Subject: [PATCH] Objects (singletons) lowering. --- .../kotlin/backend/jvm/DeclarationOrigins.kt | 1 + .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 2 +- .../backend/jvm/codegen/ClassCodegen.kt | 9 +++- .../jvm/descriptors/JvmSpecialDescriptor.kt | 2 +- .../descriptors/SpecialDescriptorsFactory.kt | 29 ++++++++++-- .../backend/jvm/lower/EnumClassLowering.kt | 2 +- .../backend/jvm/lower/ObjectClassLowering.kt | 47 +++++++++++++++++++ .../jvm/lower/SingletonReferencesLowering.kt | 6 +++ compiler/testData/ir/box/objectClass.kt | 6 +++ .../ir/IrOnlyBoxCodegenTestGenerated.java | 6 +++ 10 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt create mode 100644 compiler/testData/ir/box/objectClass.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index 3d6eefd734e..750a10dc5f9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -25,6 +25,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object DEFAULT_IMPLS : IrDeclarationOriginImpl("DEFAULT_IMPL") object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY") object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES") + object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE") } interface JvmLoweredStatementOrigin : IrStatementOrigin { 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 459c2591dcb..a662a32cdbd 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 @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.backend.jvm import org.jetbrains.kotlin.backend.jvm.lower.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -34,6 +33,7 @@ class JvmLower(val context: JvmBackendContext) { InterfaceLowering(context.state).runOnFile(irFile) InterfaceDelegationLowering(context.state).runOnFile(irFile) EnumClassLowering(context).runOnFile(irFile) + ObjectClassLowering(context).runOnFile(irFile) InitializersLowering().runOnFile(irFile) SingletonReferencesLowering(context).runOnFile(irFile) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 0a6865985ca..6c7c3a82f92 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen import com.intellij.psi.PsiElement import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSpecialDescriptor import org.jetbrains.kotlin.backend.jvm.lower.FileClassDescriptor import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.MemberCodegen.badDescriptor @@ -137,7 +138,13 @@ fun MemberDescriptor.calculateCommonFlags(): Int { throw RuntimeException("Unsupported visibility $visibility for descriptor $this") } - return flags.or(calcModalityFlag()) + flags = flags.or(calcModalityFlag()) + + if (this is JvmSpecialDescriptor) { + flags = flags or extraFlags + } + + return flags } private fun MemberDescriptor.calcModalityFlag(): Int { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmSpecialDescriptor.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmSpecialDescriptor.kt index 6a5572ee3d0..510d79dc196 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmSpecialDescriptor.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmSpecialDescriptor.kt @@ -50,7 +50,7 @@ class JvmPropertyDescriptorImpl( ) companion object { - fun createVal( + fun createStaticVal( name: Name, type: KotlinType, containingDeclaration: DeclarationDescriptor, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SpecialDescriptorsFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SpecialDescriptorsFactory.kt index c0cc7cc0923..e0d51758aa2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SpecialDescriptorsFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SpecialDescriptorsFactory.kt @@ -16,22 +16,24 @@ package org.jetbrains.kotlin.backend.jvm.descriptors -import org.jetbrains.kotlin.backend.jvm.descriptors.JvmPropertyDescriptorImpl import org.jetbrains.kotlin.backend.jvm.lower.FileClassDescriptor import org.jetbrains.kotlin.backend.jvm.lower.FileClassDescriptorImpl import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.ir.SourceManager +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.org.objectweb.asm.Opcodes import java.util.* class SpecialDescriptorsFactory(val psiSourceManager: PsiSourceManager) { - private val enumEntryFieldDescriptors = HashMap() + private val singletonFieldDescriptors = HashMap() fun getFieldDescriptorForEnumEntry(enumEntryDescriptor: ClassDescriptor): PropertyDescriptor = - enumEntryFieldDescriptors.getOrPut(enumEntryDescriptor) { + singletonFieldDescriptors.getOrPut(enumEntryDescriptor) { createEnumEntryFieldDescriptor(enumEntryDescriptor) } @@ -49,7 +51,7 @@ class SpecialDescriptorsFactory(val psiSourceManager: PsiSourceManager) { val enumClassDescriptor = enumEntryDescriptor.containingDeclaration as ClassDescriptor assert(enumClassDescriptor.kind == ClassKind.ENUM_CLASS) { "Should be enum class: $enumClassDescriptor"} - return JvmPropertyDescriptorImpl.createVal( + return JvmPropertyDescriptorImpl.createStaticVal( enumEntryDescriptor.name, enumClassDescriptor.defaultType, enumClassDescriptor, @@ -60,4 +62,23 @@ class SpecialDescriptorsFactory(val psiSourceManager: PsiSourceManager) { enumEntryDescriptor.source ) } + + fun getFieldDescriptorForObjectInstance(objectDescriptor: ClassDescriptor): PropertyDescriptor = + singletonFieldDescriptors.getOrPut(objectDescriptor) { + createObjectInstanceFieldDescriptor(objectDescriptor) + } + + private fun createObjectInstanceFieldDescriptor(objectDescriptor: ClassDescriptor): PropertyDescriptor { + assert(objectDescriptor.kind == ClassKind.OBJECT) { "Should be an object: $objectDescriptor" } + + val instanceFieldDescriptor = PropertyDescriptorImpl.create( + objectDescriptor, + Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, false, + Name.identifier("INSTANCE"), + CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, false, false + ) + instanceFieldDescriptor.setType(objectDescriptor.defaultType, listOf(), null as ReceiverParameterDescriptor?, null as ReceiverParameterDescriptor?) + + return instanceFieldDescriptor + } } \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt index 5f9ca36619a..eb570d884b0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt @@ -246,7 +246,7 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass { }) private fun createSyntheticValuesFieldDescriptor(valuesArrayType: SimpleType): PropertyDescriptorImpl { - return JvmPropertyDescriptorImpl.createVal( + return JvmPropertyDescriptorImpl.createStaticVal( Name.identifier("\$VALUES"), valuesArrayType, irClass.descriptor, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt new file mode 100644 index 00000000000..4dddcbddf0f --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl + +class ObjectClassLowering(val context: JvmBackendContext) : ClassLoweringPass { + override fun lower(irClass: IrClass) { + if (irClass.descriptor.kind != ClassKind.OBJECT) return + + val instanceFieldDescriptor = context.specialDescriptorsFactory.getFieldDescriptorForObjectInstance(irClass.descriptor) + + val constructor = irClass.descriptor.unsubstitutedPrimaryConstructor ?: + throw AssertionError("Object should have a primary constructor: ${irClass.descriptor}") + val instanceInitializer = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, constructor) + + val instanceField = IrFieldImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE, + instanceFieldDescriptor, + IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, instanceInitializer) + ) + + irClass.declarations.add(instanceField) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonReferencesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonReferencesLowering.kt index de885fbebcb..652e3c4dd76 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonReferencesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingletonReferencesLowering.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue +import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid @@ -34,4 +35,9 @@ class SingletonReferencesLowering(val context: JvmBackendContext) : BodyLowering val enumValueFieldDescriptor = context.specialDescriptorsFactory.getFieldDescriptorForEnumEntry(expression.descriptor) return IrGetFieldImpl(expression.startOffset, expression.endOffset, enumValueFieldDescriptor) } + + override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression { + val instanceFieldDescriptor = context.specialDescriptorsFactory.getFieldDescriptorForObjectInstance(expression.descriptor) + return IrGetFieldImpl(expression.startOffset, expression.endOffset, instanceFieldDescriptor) + } } \ No newline at end of file diff --git a/compiler/testData/ir/box/objectClass.kt b/compiler/testData/ir/box/objectClass.kt new file mode 100644 index 00000000000..042f5b971fb --- /dev/null +++ b/compiler/testData/ir/box/objectClass.kt @@ -0,0 +1,6 @@ +object Test { + val ok = "OK" +} + +fun box(): String = + Test.ok \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java index 45c0c35d9c2..e8fabf8b5dd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java @@ -52,4 +52,10 @@ public class IrOnlyBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTest String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/fileClassInitializers.kt"); doTest(fileName); } + + @TestMetadata("objectClass.kt") + public void testObjectClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/objectClass.kt"); + doTest(fileName); + } }