diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrCommonMemberStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrCommonMemberStorage.kt index 546a3d0336c..500828fa0d4 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrCommonMemberStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrCommonMemberStorage.kt @@ -33,6 +33,7 @@ class Fir2IrCommonMemberStorage(val firSignatureComposer: FirBasedSignatureCompo val localClassCache: MutableMap = mutableMapOf() val functionCache: ConcurrentHashMap = ConcurrentHashMap() + val dataClassGeneratedFunctionsCache: ConcurrentHashMap = ConcurrentHashMap() val constructorCache: ConcurrentHashMap = ConcurrentHashMap() diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index ba65c8f045d..9bc0d1e5e8d 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES +import org.jetbrains.kotlin.builtins.StandardNames.DATA_CLASS_COPY import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fir.* @@ -16,10 +17,7 @@ import org.jetbrains.kotlin.fir.backend.generators.isExternalParent import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.buildProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty -import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField -import org.jetbrains.kotlin.fir.declarations.utils.isExpect -import org.jetbrains.kotlin.fir.declarations.utils.isStatic -import org.jetbrains.kotlin.fir.declarations.utils.visibility +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol @@ -27,6 +25,7 @@ import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction +import org.jetbrains.kotlin.fir.resolve.getContainingClass import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.toFirRegularClass import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -54,6 +53,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource +import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled import org.jetbrains.kotlin.utils.threadLocal @@ -78,7 +78,14 @@ class Fir2IrDeclarationStorage( private val scriptCache: ConcurrentHashMap = ConcurrentHashMap() + class DataClassGeneratedFunctionsStorage { + var hashCodeSymbol: IrSimpleFunctionSymbol? = null + var toStringSymbol: IrSimpleFunctionSymbol? = null + var equalsSymbol: IrSimpleFunctionSymbol? = null + } + private val functionCache: ConcurrentHashMap = commonMemberStorage.functionCache + private val dataClassGeneratedFunctionsCache: ConcurrentHashMap = commonMemberStorage.dataClassGeneratedFunctionsCache private val constructorCache: ConcurrentHashMap = commonMemberStorage.constructorCache @@ -109,6 +116,7 @@ class Fir2IrDeclarationStorage( } } } + private val propertyCache = PropertyCacheStorage(commonMemberStorage.propertyCache, commonMemberStorage.syntheticPropertyCache) private val getterForPropertyCache: ConcurrentHashMap = commonMemberStorage.getterForPropertyCache @@ -347,6 +355,17 @@ class Fir2IrDeclarationStorage( if (function.visibility == Visibilities.Local) { return localStorage.getLocalFunctionSymbol(function) } + runIf(function.origin.generatedAnyMethod) { + val containingClass = function.getContainingClass(session)!! + val cache = dataClassGeneratedFunctionsCache.computeIfAbsent(containingClass) { DataClassGeneratedFunctionsStorage() } + val cachedFunction = when (function.nameOrSpecialName) { + OperatorNameConventions.EQUALS -> cache.equalsSymbol + OperatorNameConventions.HASH_CODE -> cache.hashCodeSymbol + OperatorNameConventions.TO_STRING -> cache.toStringSymbol + else -> return@runIf // componentN functions are the same for all sessions + } + return cachedFunction?.let(symbolsMappingForLazyClasses::remapFunctionSymbol) + } val cachedIrCallable = getCachedIrCallableSymbol( function, fakeOverrideOwnerLookupTag, @@ -441,6 +460,14 @@ class Fir2IrDeclarationStorage( irForFirSessionDependantDeclarationMap[key] = irFunctionSymbol } + function.origin.generatedAnyMethod -> { + val name = function.nameOrSpecialName + require(OperatorNameConventions.isComponentN(name) || name == DATA_CLASS_COPY) { + "Only componentN functions should be cached this way, but got: $name" + } + functionCache[function] = irFunctionSymbol + } + else -> { functionCache[function] = irFunctionSymbol } @@ -463,7 +490,15 @@ class Fir2IrDeclarationStorage( } internal fun cacheGeneratedFunction(firFunction: FirSimpleFunction, irFunction: IrSimpleFunction) { - functionCache[firFunction] = irFunction.symbol + val containingClass = firFunction.getContainingClass(session)!! + val cache = dataClassGeneratedFunctionsCache.computeIfAbsent(containingClass) { DataClassGeneratedFunctionsStorage() } + val irSymbol = irFunction.symbol + when (val name = firFunction.nameOrSpecialName) { + OperatorNameConventions.EQUALS -> cache.equalsSymbol = irSymbol + OperatorNameConventions.HASH_CODE -> cache.hashCodeSymbol = irSymbol + OperatorNameConventions.TO_STRING -> cache.toStringSymbol = irSymbol + else -> error("Only toString, hashCode and equals should be cached this way, but got $name") + } } // ------------------------------------ constructors ------------------------------------ diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt index 8bdee57aba5..848723c2e20 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DataClassMembersGenerator.kt @@ -310,8 +310,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) : Fir2IrCompon otherParameterNeeded: Boolean = false, isOperator: Boolean = false, ): IrSimpleFunction { - val signature = if (klass.symbol.classId.isLocal) null else components.signatureComposer.composeSignature(syntheticCounterpart) - val symbol = components.declarationStorage.createFunctionSymbol(signature) + val symbol = components.declarationStorage.createFunctionSymbol(signature = null) return components.irFactory.createSimpleFunction( startOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET, diff --git a/core/compiler.common/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt b/core/compiler.common/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt index a3589821af1..97b4de861ad 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt @@ -113,4 +113,9 @@ object OperatorNameConventions { RANGE_TO to "..", RANGE_UNTIL to "..<", ) + + fun isComponentN(name: Name): Boolean { + val identifier = name.identifierOrNullIfSpecial ?: return false + return COMPONENT_REGEX.matches(identifier) + } }