IDEA-337454 ExtensionPointImpl - prefer JDK immutable list instead of kotlinx immutable collections (better implemented)

GitOrigin-RevId: 5c83e0c7e87ee02e0c06a7a48f838f59f28ce5ca
This commit is contained in:
Vladimir Krivosheev
2023-11-17 15:52:40 +01:00
committed by intellij-monorepo-bot
parent 836668198c
commit a653f3cd1f
8 changed files with 156 additions and 50 deletions

View File

@@ -23,7 +23,7 @@ class ContainerDescriptor {
@JvmField var extensionPoints: PersistentList<ExtensionPointDescriptor> = persistentListOf()
@Transient var distinctExtensionPointCount: Int = -1
@Transient @JvmField var extensions: Map<String, PersistentList<ExtensionDescriptor>> = Java11Shim.INSTANCE.emptyMap()
@Transient @JvmField var extensions: Map<String, PersistentList<ExtensionDescriptor>> = Java11Shim.INSTANCE.mapOf()
fun addService(serviceDescriptor: ServiceDescriptor) {
if (_services == null) {

View File

@@ -15,7 +15,10 @@ import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.Disposer
import com.intellij.util.Java11Shim
import com.intellij.util.ThreeState
import kotlinx.collections.immutable.*
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.TestOnly
@@ -193,8 +196,10 @@ sealed class ExtensionPointImpl<T : Any>(@JvmField val name: String,
}
else {
message += " (adapter=$adapter)"
throw componentManager.createError(message, null, adapter.pluginDescriptor.pluginId,
persistentHashMapOf("threadDump" to ThreadDumper.dumpThreadsToString()))
throw componentManager.createError(/* message = */ message,
/* error = */ null,
/* pluginId = */ adapter.pluginDescriptor.pluginId,
/* attachments = */ Java11Shim.INSTANCE.mapOf("threadDump", ThreadDumper.dumpThreadsToString()))
}
}
@@ -347,15 +352,15 @@ sealed class ExtensionPointImpl<T : Any>(@JvmField val name: String,
listeners = listeners,
result = null,
duplicates = null,
extensionClassForCheck = extensionClass, adapters = adapters) ?: return Java11Shim.INSTANCE.listOf()
extensionClassForCheck = extensionClass,
adapters = adapters) ?: return Java11Shim.INSTANCE.listOf()
return Java11Shim.INSTANCE.listOf(extension)
}
val duplicates = if (this is BeanExtensionPoint<*>) null else Collections.newSetFromMap<T>(IdentityHashMap(totalSize))
val listeners = listeners
@Suppress("UNCHECKED_CAST")
val result = java.lang.reflect.Array.newInstance(extensionClass, totalSize) as Array<T>
val result = arrayOfNulls<Any>(totalSize)
var index = 0
for (adapter in adapters) {
val extension = processAdapter(adapter = adapter,
@@ -368,22 +373,13 @@ sealed class ExtensionPointImpl<T : Any>(@JvmField val name: String,
result[index++] = extension
}
}
// do not count ProcessCanceledException as a valid action to measure (later special category can be introduced if needed)
if (result.size == index) {
return Java11Shim.INSTANCE.listOf(result)
}
else {
@Suppress("UNCHECKED_CAST")
val newResult = java.lang.reflect.Array.newInstance(extensionClass, index) as Array<T>
System.arraycopy(result, 0, newResult, 0, index)
return Java11Shim.INSTANCE.listOf(newResult)
}
@Suppress("UNCHECKED_CAST")
return Java11Shim.INSTANCE.listOf(result, index) as List<T>
}
private fun processAdapter(adapter: ExtensionComponentAdapter,
listeners: List<ExtensionPointListener<T>>?,
result: Array<T>?,
result: Array<*>?,
duplicates: MutableSet<T>?,
extensionClassForCheck: Class<T>,
adapters: List<ExtensionComponentAdapter>): T? {

View File

@@ -25,10 +25,10 @@ internal class InterfaceExtensionPoint<T : Any>(
if (hasAttributes) {
val customAttributes = if (descriptor.hasExtraAttributes) {
descriptor.element?.attributes ?: Java11Shim.INSTANCE.emptyMap()
descriptor.element?.attributes ?: Java11Shim.INSTANCE.mapOf()
}
else {
Java11Shim.INSTANCE.emptyMap()
Java11Shim.INSTANCE.mapOf()
}
return AdapterWithCustomAttributes(implementationClassName = implementationClassName,
pluginDescriptor = pluginDescriptor,

View File

@@ -44,7 +44,7 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE
private final List<ChooseByNameContributor> myContributors;
protected ContributorsBasedGotoByModel(@NotNull Project project, ChooseByNameContributor @NotNull [] contributors) {
this(project, Java11Shim.INSTANCE.listOf(contributors));
this(project, List.of(contributors));
}
protected ContributorsBasedGotoByModel(@NotNull Project project, @NotNull List<ChooseByNameContributor> contributors) {

View File

@@ -0,0 +1,60 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.bootstrap
import com.intellij.concurrency.ConcurrentCollectionFactory
import com.intellij.util.Java11Shim
import com.intellij.util.containers.ConcurrentLongObjectMap
import org.jetbrains.annotations.VisibleForTesting
@VisibleForTesting
@Suppress("ReplaceJavaStaticMethodWithKotlinAnalog")
class Java11ShimImpl : Java11Shim() {
override fun <K : Any, V> copyOf(map: Map<K, V>): Map<K, V> = java.util.Map.copyOf(map)
override fun <K : Any, V> mapOf(k: K, v: V): Map<K, V> = java.util.Map.of(k, v)
override fun <E> copyOf(collection: Collection<E>): Set<E> = java.util.Set.copyOf(collection)
override fun <K : Any, V> mapOf(): Map<K, V> = java.util.Map.of()
override fun <K : Any, V> mapOf(k: K, v: V, k2: K, v2: V): Map<K, V> = java.util.Map.of(k, v, k2, v2)
override fun <V : Any> createConcurrentLongObjectMap(): ConcurrentLongObjectMap<V> {
return ConcurrentCollectionFactory.createConcurrentLongObjectMap()
}
override fun <E> listOf(): List<E> = java.util.List.of()
override fun <E> listOf(element: E): List<E> = java.util.List.of(element)
override fun <E> listOf(e1: E, e2: E): List<E> = java.util.List.of(e1, e2)
override fun <E> listOf(array: Array<E>, size: Int): List<E> {
return when (size) {
1 -> java.util.List.of(array[0])
2 -> java.util.List.of(array[0], array[1])
3 -> java.util.List.of(array[0], array[1], array[2])
4 -> java.util.List.of(array[0], array[1], array[2], array[3])
5 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4])
6 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5])
7 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6])
8 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7])
9 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8])
10 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9])
11 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9], array[10])
12 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9], array[10],
array[11])
else -> {
if (array.size == size) {
java.util.List.of(*array)
}
else {
val newResult = arrayOfNulls<Any>(size)
System.arraycopy(array, 0, newResult, 0, size)
@Suppress("UNCHECKED_CAST", "KotlinConstantConditions")
return java.util.List.of(*newResult) as List<E>
}
}
}
}
}

View File

@@ -6,7 +6,6 @@ package com.intellij.platform.ide.bootstrap
import com.intellij.BundleBase
import com.intellij.accessibility.enableScreenReaderSupportIfNecessary
import com.intellij.concurrency.ConcurrentCollectionFactory
import com.intellij.diagnostic.*
import com.intellij.ide.*
import com.intellij.ide.bootstrap.*
@@ -35,7 +34,6 @@ import com.intellij.ui.mac.screenmenu.Menu
import com.intellij.ui.scale.JBUIScale
import com.intellij.ui.svg.SvgCacheManager
import com.intellij.util.*
import com.intellij.util.containers.ConcurrentLongObjectMap
import com.intellij.util.containers.SLRUMap
import com.intellij.util.io.*
import com.intellij.util.lang.ZipFilePool
@@ -44,7 +42,6 @@ import io.opentelemetry.sdk.OpenTelemetrySdkBuilder
import kotlinx.coroutines.*
import kotlinx.coroutines.debug.internal.DebugProbesImpl
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.VisibleForTesting
import java.awt.Toolkit
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
@@ -725,24 +722,3 @@ interface AppStarter {
fun importFinished(newConfigDir: Path) {}
}
@VisibleForTesting
@Suppress("ReplaceJavaStaticMethodWithKotlinAnalog")
class Java11ShimImpl : Java11Shim() {
override fun <K : Any, V> copyOf(map: Map<K, V>) = java.util.Map.copyOf(map)
override fun <K : Any, V> mapOf(k: K, v: V): Map<K, V> = java.util.Map.of(k, v)
override fun <E> copyOf(collection: Collection<E>): Set<E> = java.util.Set.copyOf(collection)
override fun <K : Any, V> emptyMap(): Map<K, V> = java.util.Map.of()
override fun <V : Any> createConcurrentLongObjectMap(): ConcurrentLongObjectMap<V> {
return ConcurrentCollectionFactory.createConcurrentLongObjectMap()
}
override fun <E> listOf(): List<E> = java.util.List.of()
override fun <E> listOf(element: E): List<E> = java.util.List.of(element)
override fun <E> listOf(array: Array<E>): List<E> = java.util.List.of(*array)
}

View File

@@ -1,4 +1,6 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplacePutWithAssignment", "ReplaceJavaStaticMethodWithKotlinAnalog")
package com.intellij.util
import com.intellij.util.containers.ConcurrentLongObjectMap
@@ -15,19 +17,28 @@ abstract class Java11Shim {
override fun <K : Any, V> mapOf(k: K, v: V): Map<K, V> = Collections.singletonMap(k, v)
override fun <K : Any, V> mapOf(k: K, v: V, k2: K, v2: V): Map<K, V> {
val map = HashMap<K, V>(2)
map.put(k, v)
map.put(k2, v2)
return map
}
override fun <E> copyOf(collection: Collection<E>): Set<E> = Collections.unmodifiableSet(HashSet(collection))
override fun <V : Any> createConcurrentLongObjectMap(): ConcurrentLongObjectMap<V> {
return ConcurrentLongObjectHashMap()
}
override fun <K : Any, V> emptyMap(): Map<K, V> = Collections.emptyMap()
override fun <K : Any, V> mapOf(): Map<K, V> = Collections.emptyMap()
override fun <E> listOf(): List<E> = Collections.emptyList()
override fun <E> listOf(element: E): List<E> = Collections.singletonList(element)
override fun <E> listOf(array: Array<E>) = array.asList()
override fun <E> listOf(e1: E, e2: E): List<E> = Arrays.asList(e1, e2)
override fun <E> listOf(array: Array<E>, size: Int) = if (array.size == size) array.asList() else array.asList().subList(0, size)
}
}
@@ -35,7 +46,9 @@ abstract class Java11Shim {
abstract fun <K : Any, V> mapOf(k: K, v: V): Map<K, V>
abstract fun <K : Any, V> emptyMap(): Map<K, V>
abstract fun <K : Any, V> mapOf(k: K, v: V, k2: K, v2: V): Map<K, V>
abstract fun <K : Any, V> mapOf(): Map<K, V>
abstract fun <E> copyOf(collection: Collection<E>): Set<E>
@@ -43,7 +56,9 @@ abstract class Java11Shim {
abstract fun <E> listOf(element: E): List<E>
abstract fun <E> listOf(array: Array<E>): List<E>
abstract fun <E> listOf(e1: E, e2: E): List<E>
abstract fun <E> listOf(array: Array<E>, size: Int): List<E>
abstract fun <V : Any> createConcurrentLongObjectMap(): ConcurrentLongObjectMap<V>
}

View File

@@ -1,7 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplacePutWithAssignment")
package com.intellij.util.containers
import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.Java11Shim
import com.intellij.util.SmartList
import com.intellij.util.lang.CompoundRuntimeException
import org.jetbrains.annotations.ApiStatus.Experimental
@@ -18,6 +21,62 @@ fun <K, V> MutableMap<K, MutableList<V>>.remove(key: K, value: V) {
}
}
/**
* Do not use it for a concurrent map (doesn't make sense).
*/
@Internal
@Experimental
fun <K : Any, V> Map<K, V>.without(key: K): Map<K, V> {
if (!containsKey(key)) {
return this
}
else if (size == 1) {
return Java11Shim.INSTANCE.mapOf()
}
else {
val result = HashMap<K, V>(size, 0.5f)
result.putAll(this)
result.remove(key)
return result
}
}
/**
* Do not use it for a concurrent map (doesn't make sense).
*/
@Internal
@Experimental
fun <K : Any, V> Map<K, V>.with(key: K, value: V): Map<K, V> {
val size = size
if (size == 0) {
return Java11Shim.INSTANCE.mapOf(key, value)
}
// do not use a java-immutable map, same as ours UnmodifiableHashMap and fastutil it uses open addressing hashing
// - https://stackoverflow.com/a/16303438
val result = HashMap<K, V>(size + 1, 0.5f)
result.putAll(this)
result.put(key, value)
return result
}
/**
* Do not use it for a concurrent map (doesn't make sense).
*/
@Internal
@Experimental
fun <K : Any, V> Map<K, V>.withAll(otherMap: Map<K, V>): Map<K, V> {
val totalSize = size + otherMap.size
if (totalSize == 0) {
return Java11Shim.INSTANCE.mapOf()
}
val result = HashMap<K, V>(totalSize, 0.5f)
result.putAll(this)
result.putAll(otherMap)
return result
}
fun <K, V> MutableMap<K, MutableList<V>>.putValue(key: K, value: V) {
val list = get(key)
if (list == null) {