diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt index 0dc3bdcbe4e..3706691a1d1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionsService.kt @@ -38,7 +38,7 @@ class FirRegisteredExtension

( class FirExtensionsService( val session: FirSession ) : ComponentArrayOwner>(), FirSessionComponent { - companion object : ComponentTypeRegistry>() { + companion object : TypeRegistry>() { inline fun > registeredExtensions(): ReadOnlyProperty> { val accessor = generateAccessor(P::class) return object : ReadOnlyProperty> { @@ -51,7 +51,7 @@ class FirExtensionsService( private fun createMultimap(): Multimap = LinkedHashMultimap.create() } - override val typeRegistry: ComponentTypeRegistry> + override val typeRegistry: TypeRegistry> get() = Companion fun

registerExtensions(extensionClass: KClass

, extensionFactories: List>) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt index ff3528c44bd..e31c9897ffd 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt @@ -8,16 +8,16 @@ package org.jetbrains.kotlin.fir import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.types.impl.* -import org.jetbrains.kotlin.fir.utils.ComponentArrayAccessor +import org.jetbrains.kotlin.fir.utils.ArrayMapAccessor import org.jetbrains.kotlin.fir.utils.ComponentArrayOwner -import org.jetbrains.kotlin.fir.utils.ComponentTypeRegistry +import org.jetbrains.kotlin.fir.utils.TypeRegistry import org.jetbrains.kotlin.utils.Jsr305State interface FirSessionComponent abstract class FirSession(val sessionProvider: FirSessionProvider?) : ComponentArrayOwner() { - companion object : ComponentTypeRegistry() { - inline fun sessionComponentAccessor(): ComponentArrayAccessor { + companion object : TypeRegistry() { + inline fun sessionComponentAccessor(): ArrayMapAccessor { return generateAccessor(T::class) } } @@ -28,7 +28,7 @@ abstract class FirSession(val sessionProvider: FirSessionProvider?) : ComponentA val builtinTypes: BuiltinTypes = BuiltinTypes() - final override val typeRegistry: ComponentTypeRegistry = Companion + final override val typeRegistry: TypeRegistry = Companion } interface FirSessionProvider { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationAttributes.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationAttributes.kt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt new file mode 100644 index 00000000000..01f4fc63701 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMap.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.utils + +sealed class ArrayMap { + abstract val size: Int + + abstract operator fun set(index: Int, value: T) + abstract operator fun get(index: Int): T? +} + +internal object EmptyArrayMap : ArrayMap() { + override val size: Int + get() = 0 + + override fun set(index: Int, value: Nothing) { + throw IllegalStateException() + } + + override fun get(index: Int): Nothing? { + return null + } +} + +internal class OneElementArrayMap(val value: T, val index: Int) : ArrayMap() { + override val size: Int + get() = 1 + + override fun set(index: Int, value: T) { + throw IllegalStateException() + } + + override fun get(index: Int): T? { + return if (index == this.index) value else null + } +} + +internal class ArrayMapImpl : ArrayMap() { + companion object { + private const val DEFAULT_SIZE = 20 + private const val INCREASE_K = 2 + } + + override var size: Int = 0 + private set + + private var data = arrayOfNulls(DEFAULT_SIZE) + private fun ensureCapacity(index: Int) { + if (data.size < index) { + data = data.copyOf(data.size * INCREASE_K) + } + } + + override operator fun set(index: Int, value: T) { + ensureCapacity(index) + data[index] = value + + size++ + } + + override operator fun get(index: Int): T? { + @Suppress("UNCHECKED_CAST") + return data.getOrNull(index) as T? + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt new file mode 100644 index 00000000000..391a3f8a9d2 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ArrayMapOwner.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.utils + +import java.util.* +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + +abstract class AbstractArrayMapOwner { + protected abstract val arrayMap: ArrayMap + protected abstract val typeRegistry: TypeRegistry + + abstract class AbstractArrayMapAccessor( + protected val key: KClass, + protected val id: Int + ) { + protected fun extractValue(thisRef: AbstractArrayMapOwner): T? { + @Suppress("UNCHECKED_CAST") + return thisRef.arrayMap[id] as T? + } + } + + protected abstract fun registerComponent(tClass: KClass, value: V) +} + +class ArrayMapAccessor( + key: KClass, + id: Int +) : AbstractArrayMapOwner.AbstractArrayMapAccessor(key, id), ReadOnlyProperty, V> { + override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T { + return extractValue(thisRef) ?: error("No '$key'($id) in array owner: $thisRef") + } +} + +class NullableArrayMapAccessor( + key: KClass, + id: Int +) : AbstractArrayMapOwner.AbstractArrayMapAccessor(key, id), ReadOnlyProperty, V?> { + override fun getValue(thisRef: AbstractArrayMapOwner, property: KProperty<*>): T? { + return extractValue(thisRef) + } +} + +abstract class TypeRegistry { + private val idPerType = HashMap, Int>() + + fun generateAccessor(kClass: KClass): ArrayMapAccessor { + return ArrayMapAccessor(kClass, getId(kClass)) + } + + fun generateNullableAccessor(kClass: KClass): NullableArrayMapAccessor { + return NullableArrayMapAccessor(kClass, getId(kClass)) + } + + fun getId(kClass: KClass): Int { + return idPerType.getOrPut(kClass) { idPerType.size } + } +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt new file mode 100644 index 00000000000..32930a3f9dc --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/AttributeArrayOwner.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.utils + +import kotlin.reflect.KClass + +/** + * [AttributeArrayOwner] based on different implementations of [ArrayMap] and switches them + * depending on array map fullness + * [AttributeArrayOwner] can be used in classes with many instances, + * like user data for Fir elements or attributes for cone types + */ +abstract class AttributeArrayOwner : AbstractArrayMapOwner() { + @Suppress("UNCHECKED_CAST") + final override var arrayMap: ArrayMap = EmptyArrayMap as ArrayMap + private set + + final override fun registerComponent(tClass: KClass, value: T) { + val id = typeRegistry.getId(tClass) + when (arrayMap.size) { + 0 -> { + arrayMap = OneElementArrayMap(value, id) + return + } + + 1 -> { + arrayMap = ArrayMapImpl().apply { + val map = arrayMap as OneElementArrayMap + this[map.index] = map.value + } + } + } + + arrayMap[id] = value + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt deleted file mode 100644 index 49bbe8b147a..00000000000 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArray.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.fir.utils - -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KClass -import kotlin.reflect.KProperty - -abstract class ComponentArrayOwner { - internal val componentArray: ComponentArray = ComponentArray() - protected abstract val typeRegistry: ComponentTypeRegistry - - protected fun registerComponent(tClass: KClass, value: V) { - componentArray[(typeRegistry.getId(tClass))] = value - } - - protected operator fun get(tClass: KClass): V { - return componentArray[typeRegistry.getId(tClass)] - } -} - - -abstract class ComponentTypeRegistry { - private val idPerType = mutableMapOf, Int>() - - fun generateAccessor(kClass: KClass): ComponentArrayAccessor { - return ComponentArrayAccessor(kClass, getId(kClass)) - } - - fun getId(kClass: KClass): Int { - return idPerType.getOrPut(kClass) { idPerType.size } - } -} - - -class ComponentArrayAccessor( - private val key: KClass, - private val id: Int -) : ReadOnlyProperty, V> { - override fun getValue(thisRef: ComponentArrayOwner, property: KProperty<*>): T { - @Suppress("UNCHECKED_CAST") - return thisRef.componentArray[id] as T? ?: error("No '$key'($id) component in session: $thisRef") - } -} - -class ComponentArray { - companion object { - private const val DEFAULT_SIZE = 20 - private const val INCREASE_K = 2 - } - - private var data = arrayOfNulls(DEFAULT_SIZE) - private fun ensureCapacity(index: Int) { - if (data.size < index) { - data = data.copyOf(data.size * INCREASE_K) - } - } - - operator fun set(index: Int, value: T) { - ensureCapacity(index) - data[index] = value - } - - operator fun get(index: Int): T { - @Suppress("UNCHECKED_CAST") - return data.getOrNull(index) as T - } -} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt new file mode 100644 index 00000000000..26e33286940 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/utils/ComponentArrayOwner.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.utils + +import kotlin.reflect.KClass + +/** + * [ComponentArrayOwner] based on [ArrayMap] with flexible size and should be used for + * storing services in entities with limited number of instances, like FirSession + */ +abstract class ComponentArrayOwner : AbstractArrayMapOwner() { + final override val arrayMap: ArrayMap = + ArrayMapImpl() + + final override fun registerComponent(tClass: KClass, value: V) { + arrayMap[typeRegistry.getId(tClass)] = value + } + + protected operator fun get(key: KClass): V { + val id = typeRegistry.getId(key) + return arrayMap[id] ?: error("No '$key'($id) component in array: $this") + } +} \ No newline at end of file