JVM_IR: extract cached fields into a separate class

This commit is contained in:
Georgy Bronnikov
2021-05-12 11:49:58 +03:00
committed by TeamCityServer
parent 50068607b9
commit a328ebc889
5 changed files with 69 additions and 55 deletions
@@ -67,7 +67,7 @@ class JvmBackendContext(
val methodSignatureMapper = MethodSignatureMapper(this)
internal val innerClassesSupport = JvmInnerClassesSupport(irFactory)
internal val cachedDeclarations = JvmCachedDeclarations(this, state.languageVersionSettings)
internal val cachedDeclarations = JvmCachedDeclarations(this, CachedFieldsForObjectInstances(irFactory, state.languageVersionSettings))
override val mapping: Mapping = DefaultMapping()
@@ -32,10 +32,9 @@ import java.util.concurrent.ConcurrentHashMap
class JvmCachedDeclarations(
private val context: JvmBackendContext,
private val languageVersionSettings: LanguageVersionSettings
val fieldsForObjectInstances: CachedFieldsForObjectInstances,
) {
private val singletonFieldDeclarations = ConcurrentHashMap<IrSymbolOwner, IrField>()
private val interfaceCompanionFieldDeclarations = ConcurrentHashMap<IrSymbolOwner, IrField>()
private val staticBackingFields = ConcurrentHashMap<IrProperty, IrField>()
private val staticCompanionDeclarations = ConcurrentHashMap<IrSimpleFunction, Pair<IrSimpleFunction, IrSimpleFunction>>()
@@ -58,50 +57,9 @@ class JvmCachedDeclarations(
}
}
fun getFieldForObjectInstance(singleton: IrClass): IrField =
singletonFieldDeclarations.getOrPut(singleton) {
val originalVisibility = singleton.visibility
val isNotMappedCompanion = singleton.isCompanion && !singleton.isMappedIntrinsicCompanionObject()
val useProperVisibilityForCompanion =
languageVersionSettings.supportsFeature(LanguageFeature.ProperVisibilityForCompanionObjectInstanceField)
&& singleton.isCompanion
&& !singleton.parentAsClass.isInterface
context.irFactory.buildField {
name = if (isNotMappedCompanion) singleton.name else Name.identifier(JvmAbi.INSTANCE_FIELD)
type = singleton.defaultType
origin = IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
isFinal = true
isStatic = true
visibility = when {
!useProperVisibilityForCompanion -> DescriptorVisibilities.PUBLIC
originalVisibility == DescriptorVisibilities.PROTECTED -> JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY
else -> originalVisibility
}
fun getFieldForObjectInstance(singleton: IrClass): IrField = fieldsForObjectInstances.getFieldForObjectInstance(singleton)
}.apply {
parent = if (isNotMappedCompanion) singleton.parent else singleton
}
}
private fun IrClass.isMappedIntrinsicCompanionObject() =
isCompanion && classId?.let { CompanionObjectMapping.isMappedIntrinsicCompanionObjectClassId(it) } == true
fun getPrivateFieldForObjectInstance(singleton: IrClass): IrField =
if (singleton.isCompanion && singleton.parentAsClass.isJvmInterface)
interfaceCompanionFieldDeclarations.getOrPut(singleton) {
context.irFactory.buildField {
name = Name.identifier("\$\$INSTANCE")
type = singleton.defaultType
origin = JvmLoweredDeclarationOrigin.INTERFACE_COMPANION_PRIVATE_INSTANCE
isFinal = true
isStatic = true
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
}.apply {
parent = singleton
}
}
else
getFieldForObjectInstance(singleton)
fun getPrivateFieldForObjectInstance(singleton: IrClass): IrField = fieldsForObjectInstances.getPrivateFieldForObjectInstance(singleton)
fun getStaticBackingField(irProperty: IrProperty): IrField? {
// Only fields defined directly in objects should be made static.
@@ -136,7 +94,7 @@ class JvmCachedDeclarations(
}
initializer = oldField.initializer?.patchDeclarationParents(this)
oldField.replaceThisByStaticReference(this@JvmCachedDeclarations, oldParent, oldParent.thisReceiver!!)
oldField.replaceThisByStaticReference(fieldsForObjectInstances, oldParent, oldParent.thisReceiver!!)
origin = if (irProperty.parentAsClass.isCompanion) JvmLoweredDeclarationOrigin.COMPANION_PROPERTY_BACKING_FIELD else origin
}
}
@@ -315,3 +273,60 @@ class JvmCachedDeclarations(
}
}
}
/*
This class keeps track of singleton fields for instances of object classes.
*/
class CachedFieldsForObjectInstances(
private val irFactory: IrFactory,
private val languageVersionSettings: LanguageVersionSettings,
) {
private val singletonFieldDeclarations = ConcurrentHashMap<IrSymbolOwner, IrField>()
private val interfaceCompanionFieldDeclarations = ConcurrentHashMap<IrSymbolOwner, IrField>()
fun getFieldForObjectInstance(singleton: IrClass): IrField =
singletonFieldDeclarations.getOrPut(singleton) {
val originalVisibility = singleton.visibility
val isNotMappedCompanion = singleton.isCompanion && !singleton.isMappedIntrinsicCompanionObject()
val useProperVisibilityForCompanion =
languageVersionSettings.supportsFeature(LanguageFeature.ProperVisibilityForCompanionObjectInstanceField)
&& singleton.isCompanion
&& !singleton.parentAsClass.isInterface
irFactory.buildField {
name = if (isNotMappedCompanion) singleton.name else Name.identifier(JvmAbi.INSTANCE_FIELD)
type = singleton.defaultType
origin = IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
isFinal = true
isStatic = true
visibility = when {
!useProperVisibilityForCompanion -> DescriptorVisibilities.PUBLIC
originalVisibility == DescriptorVisibilities.PROTECTED -> JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY
else -> originalVisibility
}
}.apply {
parent = if (isNotMappedCompanion) singleton.parent else singleton
}
}
private fun IrClass.isMappedIntrinsicCompanionObject() =
isCompanion && classId?.let { CompanionObjectMapping.isMappedIntrinsicCompanionObjectClassId(it) } == true
fun getPrivateFieldForObjectInstance(singleton: IrClass): IrField =
if (singleton.isCompanion && singleton.parentAsClass.isJvmInterface)
interfaceCompanionFieldDeclarations.getOrPut(singleton) {
irFactory.buildField {
name = Name.identifier("\$\$INSTANCE")
type = singleton.defaultType
origin = JvmLoweredDeclarationOrigin.INTERFACE_COMPANION_PRIVATE_INSTANCE
isFinal = true
isStatic = true
visibility = JavaDescriptorVisibilities.PACKAGE_VISIBILITY
}.apply {
parent = singleton
}
}
else
getFieldForObjectInstance(singleton)
}
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.ir
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.lower.IrLoweringContext
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmCachedDeclarations
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.JvmSymbols
import org.jetbrains.kotlin.backend.jvm.*
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineOnly
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.codegen.representativeUpperBound
@@ -232,7 +229,7 @@ fun IrExpression.isSmartcastFromHigherThanNullable(context: JvmBackendContext):
}
fun IrElement.replaceThisByStaticReference(
cachedDeclarations: JvmCachedDeclarations,
cachedFields: CachedFieldsForObjectInstances,
irClass: IrClass,
oldThisReceiverParameter: IrValueParameter
) {
@@ -242,7 +239,7 @@ fun IrElement.replaceThisByStaticReference(
IrGetFieldImpl(
expression.startOffset,
expression.endOffset,
cachedDeclarations.getPrivateFieldForObjectInstance(irClass).symbol,
cachedFields.getPrivateFieldForObjectInstance(irClass).symbol,
irClass.defaultType
)
} else super.visitGetValue(expression)
@@ -87,7 +87,9 @@ private class SingletonObjectJvmStaticTransformer(val context: JvmBackendContext
// dispatch receiver parameter is already null for synthetic property annotation methods
function.dispatchReceiverParameter?.let { oldDispatchReceiverParameter ->
function.dispatchReceiverParameter = null
function.replaceThisByStaticReference(context.cachedDeclarations, declaration, oldDispatchReceiverParameter)
function.replaceThisByStaticReference(
context.cachedDeclarations.fieldsForObjectInstances, declaration, oldDispatchReceiverParameter
)
}
}
}
@@ -102,7 +102,7 @@ private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendCon
IrAnonymousInitializerImpl(startOffset, endOffset, origin, newSymbol, isStatic = true).apply {
parent = newParent
body = this@with.body.patchDeclarationParents(newParent)
replaceThisByStaticReference(context.cachedDeclarations, oldParent, oldParent.thisReceiver!!)
replaceThisByStaticReference(context.cachedDeclarations.fieldsForObjectInstances, oldParent, oldParent.thisReceiver!!)
}
}