[FE] Use FQN instead of KClass in TypeRegistry
TypeRegistry is the static map which contains mapping between type of session component and its index in the session array. Originally `KClass` of a component was used as a key in this map, which worked pretty well for compiler components. But there was a problem with components from plugins and Kotlin daemon: in compilation with daemon we keep TypeRegistry between compilations. But for each compilation we load plugins from jar, which brings to the situation when after N compilations there is N entries in TypeRegistry map with different KClass'es for same extension component. This not only causes AIOBE but also introduces the memory leak, because we keep reference to KClass which is not used anymore So to fix this issue it's enough to just store FQN of component in TypeRegistry instead of KClass There are no tests in this commit, but they will be added in next commit relevant to scripting. With those commits we will have gradle integration tests which uses Kotlin compiler daemon and registers a compiler plugin for scripting ^KT-55023 Fixed
This commit is contained in:
committed by
Space Team
parent
890418f6b7
commit
c44993e586
@@ -7,13 +7,12 @@ package org.jetbrains.kotlin.fir.util
|
||||
|
||||
import org.jetbrains.kotlin.util.TypeRegistry
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class ConeTypeRegistry<K : Any, V : Any> : TypeRegistry<K, V>() {
|
||||
override fun <T : K> ConcurrentHashMap<KClass<out K>, Int>.customComputeIfAbsent(
|
||||
kClass: KClass<T>,
|
||||
compute: (KClass<out K>) -> Int
|
||||
override fun ConcurrentHashMap<String, Int>.customComputeIfAbsent(
|
||||
key: String,
|
||||
compute: (String) -> Int
|
||||
): Int {
|
||||
return this.computeIfAbsent(kClass, compute)
|
||||
return this.computeIfAbsent(key, compute)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -6,26 +6,27 @@
|
||||
package org.jetbrains.kotlin.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class FirDeclarationRendererWithAttributes : FirDeclarationRenderer() {
|
||||
override fun FirDeclaration.renderDeclarationAttributes() {
|
||||
if (attributes.isNotEmpty()) {
|
||||
val attributes = getAttributesWithValues().mapNotNull { (klass, value) ->
|
||||
value?.let { klass.simpleName to value.renderAsDeclarationAttributeValue() }
|
||||
value?.let { klass to value.renderAsDeclarationAttributeValue() }
|
||||
}.joinToString { (name, value) -> "$name=$value" }
|
||||
printer.print("[$attributes] ")
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirDeclaration.getAttributesWithValues(): List<Pair<KClass<out FirDeclarationDataKey>, Any?>> {
|
||||
private fun FirDeclaration.getAttributesWithValues(): List<Pair<String, Any?>> {
|
||||
val attributesMap = FirDeclarationDataRegistry.allValuesThreadUnsafeForRendering()
|
||||
return attributesMap.entries.sortedBy { it.key.simpleName }.map { (klass, index) -> klass to attributes[index] }
|
||||
return attributesMap.entries
|
||||
.map { it.key.substringAfterLast(".") to it.value }
|
||||
.sortedBy { it.first }
|
||||
.map { (klass, index) -> klass to attributes[index] }
|
||||
}
|
||||
|
||||
private fun Any.renderAsDeclarationAttributeValue() = when (this) {
|
||||
@@ -34,4 +35,4 @@ open class FirDeclarationRendererWithAttributes : FirDeclarationRenderer() {
|
||||
is FirProperty -> symbol.callableId.toString()
|
||||
else -> toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,9 @@ class NullableArrayMapAccessor<K : Any, V : Any, T : V>(
|
||||
}
|
||||
|
||||
abstract class TypeRegistry<K : Any, V : Any> {
|
||||
private val idPerType = ConcurrentHashMap<KClass<out K>, Int>()
|
||||
private val idPerType = ConcurrentHashMap<String, Int>()
|
||||
private val idCounter = AtomicInteger(0)
|
||||
|
||||
|
||||
fun <T : V, KK : K> generateAccessor(kClass: KClass<KK>, default: T? = null): ArrayMapAccessor<K, V, T> {
|
||||
return ArrayMapAccessor(kClass, getId(kClass), default)
|
||||
}
|
||||
@@ -78,15 +77,22 @@ abstract class TypeRegistry<K : Any, V : Any> {
|
||||
}
|
||||
|
||||
fun <T : K> getId(kClass: KClass<T>): Int {
|
||||
return idPerType.customComputeIfAbsent(kClass) { idCounter.getAndIncrement() }
|
||||
return idPerType.customComputeIfAbsent(kClass.qualifiedName!!) { idCounter.getAndIncrement() }
|
||||
}
|
||||
|
||||
abstract fun <T : K> ConcurrentHashMap<KClass<out K>, Int>.customComputeIfAbsent(
|
||||
kClass: KClass<T>,
|
||||
compute: (KClass<out K>) -> Int
|
||||
/*
|
||||
* This function is needed for compatibility with JDK 6
|
||||
* ArrayMap and other infrastructure is used in KotlinType, declared in :core:descriptors module, which is
|
||||
* compiled against JDK 6 (because it's used in kotlin-reflect, which is still compatible with Java 6)
|
||||
* So the problem is that JDK 6 does not have thread-safe computeIfAbsent for ConcurrentHashMap,
|
||||
* and we need this method to add ability to provide thread-safe implementation by hand
|
||||
*/
|
||||
abstract fun ConcurrentHashMap<String, Int>.customComputeIfAbsent(
|
||||
key: String,
|
||||
compute: (String) -> Int
|
||||
): Int
|
||||
|
||||
fun allValuesThreadUnsafeForRendering(): Map<KClass<out K>, Int> {
|
||||
fun allValuesThreadUnsafeForRendering(): Map<String, Int> {
|
||||
return idPerType
|
||||
}
|
||||
|
||||
|
||||
@@ -42,12 +42,12 @@ class TypeAttributes private constructor(attributes: List<TypeAttribute<*>>) : A
|
||||
return generateNullableAccessor<TypeAttribute<*>, T>(T::class) as ReadOnlyProperty<TypeAttributes, T?>
|
||||
}
|
||||
|
||||
override fun <T : TypeAttribute<*>> ConcurrentHashMap<KClass<out TypeAttribute<*>>, Int>.customComputeIfAbsent(
|
||||
kClass: KClass<T>,
|
||||
compute: (KClass<out TypeAttribute<*>>) -> Int
|
||||
override fun ConcurrentHashMap<String, Int>.customComputeIfAbsent(
|
||||
key: String,
|
||||
compute: (String) -> Int
|
||||
): Int {
|
||||
return this[kClass] ?: synchronized(this) {
|
||||
this[kClass] ?: compute(kClass).also { this.putIfAbsent(kClass, it) }
|
||||
return this[key] ?: synchronized(this) {
|
||||
this[key] ?: compute(key).also { this.putIfAbsent(key, it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user