[FIR2IR] Properly cache generated data/value class members
FIR instances of generated toString/hashCode/equals are session dependant, so we need some cache, which operates only session-independent stuff. Pair of `FirClass` and `Name` was chosen here Previously SymbolTable played the role of this cache (with signatures as keys). But it should be replaced in scope of KT-66341 and KT-64990
This commit is contained in:
committed by
Space Team
parent
52f6868b74
commit
e8f8399af4
@@ -33,6 +33,7 @@ class Fir2IrCommonMemberStorage(val firSignatureComposer: FirBasedSignatureCompo
|
||||
val localClassCache: MutableMap<FirClass, IrClass> = mutableMapOf()
|
||||
|
||||
val functionCache: ConcurrentHashMap<FirFunction, IrSimpleFunctionSymbol> = ConcurrentHashMap()
|
||||
val dataClassGeneratedFunctionsCache: ConcurrentHashMap<FirClass, Fir2IrDeclarationStorage.DataClassGeneratedFunctionsStorage> = ConcurrentHashMap()
|
||||
|
||||
val constructorCache: ConcurrentHashMap<FirConstructor, IrConstructorSymbol> = ConcurrentHashMap()
|
||||
|
||||
|
||||
+40
-5
@@ -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<FirScript, IrScript> = ConcurrentHashMap()
|
||||
|
||||
class DataClassGeneratedFunctionsStorage {
|
||||
var hashCodeSymbol: IrSimpleFunctionSymbol? = null
|
||||
var toStringSymbol: IrSimpleFunctionSymbol? = null
|
||||
var equalsSymbol: IrSimpleFunctionSymbol? = null
|
||||
}
|
||||
|
||||
private val functionCache: ConcurrentHashMap<FirFunction, IrSimpleFunctionSymbol> = commonMemberStorage.functionCache
|
||||
private val dataClassGeneratedFunctionsCache: ConcurrentHashMap<FirClass, DataClassGeneratedFunctionsStorage> = commonMemberStorage.dataClassGeneratedFunctionsCache
|
||||
|
||||
private val constructorCache: ConcurrentHashMap<FirConstructor, IrConstructorSymbol> = commonMemberStorage.constructorCache
|
||||
|
||||
@@ -109,6 +116,7 @@ class Fir2IrDeclarationStorage(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val propertyCache = PropertyCacheStorage(commonMemberStorage.propertyCache, commonMemberStorage.syntheticPropertyCache)
|
||||
private val getterForPropertyCache: ConcurrentHashMap<IrSymbol, IrSimpleFunctionSymbol> =
|
||||
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 ------------------------------------
|
||||
|
||||
+1
-2
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user