Objects (singletons) lowering.

This commit is contained in:
Dmitry Petrov
2016-09-28 15:44:16 +03:00
parent 866def0d20
commit f423369327
10 changed files with 102 additions and 8 deletions
@@ -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 {
@@ -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)
}
@@ -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 {
@@ -50,7 +50,7 @@ class JvmPropertyDescriptorImpl(
)
companion object {
fun createVal(
fun createStaticVal(
name: Name,
type: KotlinType,
containingDeclaration: DeclarationDescriptor,
@@ -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<ClassDescriptor, PropertyDescriptor>()
private val singletonFieldDescriptors = HashMap<ClassDescriptor, PropertyDescriptor>()
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
}
}
@@ -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,
@@ -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)
}
}
@@ -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)
}
}
+6
View File
@@ -0,0 +1,6 @@
object Test {
val ok = "OK"
}
fun box(): String =
Test.ok
@@ -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);
}
}