FIR IDE: allow the same entity to be accessed from different threads

This commit is contained in:
Ilya Kirillov
2020-07-06 19:24:58 +03:00
parent 4c08dfb238
commit 964becf138
3 changed files with 11 additions and 18 deletions
@@ -33,7 +33,6 @@ interface ValidityOwnerByValidityToken : ValidityOwner {
class ReadActionConfinementValidityToken(project: Project) : ValidityOwner { class ReadActionConfinementValidityToken(project: Project) : ValidityOwner {
private val modificationTracker = KotlinModificationTrackerService.getInstance(project).modificationTracker private val modificationTracker = KotlinModificationTrackerService.getInstance(project).modificationTracker
private val ownerThread = Thread.currentThread()
private val onCreatedTimeStamp = modificationTracker.modificationCount private val onCreatedTimeStamp = modificationTracker.modificationCount
@@ -41,7 +40,6 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityOwner {
val application = ApplicationManager.getApplication() val application = ApplicationManager.getApplication()
if (application.isDispatchThread) return false if (application.isDispatchThread) return false
if (!application.isReadAccessAllowed) return false if (!application.isReadAccessAllowed) return false
if (ownerThread != Thread.currentThread()) return false
return onCreatedTimeStamp == modificationTracker.modificationCount return onCreatedTimeStamp == modificationTracker.modificationCount
} }
@@ -49,9 +47,6 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityOwner {
val application = ApplicationManager.getApplication() val application = ApplicationManager.getApplication()
if (application.isDispatchThread) return "Called in EDT thread" if (application.isDispatchThread) return "Called in EDT thread"
if (!application.isReadAccessAllowed) return "Called outside read action" if (!application.isReadAccessAllowed) return "Called outside read action"
if (ownerThread != Thread.currentThread()) {
return "Called outside the thread was created in (was created in $ownerThread, but accessed in ${Thread.currentThread()}"
}
if (onCreatedTimeStamp != modificationTracker.modificationCount) return "PSI has changed since creation" if (onCreatedTimeStamp != modificationTracker.modificationCount) return "PSI has changed since creation"
error("Getting invalidation reason for valid invalidatable") error("Getting invalidation reason for valid invalidatable")
} }
@@ -5,9 +5,9 @@
package org.jetbrains.kotlin.idea.frontend.api.fir package org.jetbrains.kotlin.idea.frontend.api.fir
import com.google.common.collect.MapMaker
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
@@ -41,6 +41,9 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
/**
* Maps FirElement to KtSymbol & ConeType to KtType, thread safe
*/
internal class KtSymbolByFirBuilder( internal class KtSymbolByFirBuilder(
firProvider: FirSymbolProvider, firProvider: FirSymbolProvider,
typeCheckerContext: ConeTypeCheckerContext, typeCheckerContext: ConeTypeCheckerContext,
@@ -149,8 +152,7 @@ internal class KtSymbolByFirBuilder(
} }
private class BuilderCache<From, To> { private class BuilderCache<From, To> {
// the capacity & load factor values here are default ones which are used ing java.util.Map private val cache = MapMaker().weakKeys().makeMap<From, To>()
private val cache = ContainerUtil.createWeakMap<From, To>(16, .75f, ContainerUtil.identityStrategy())
inline fun <reified S : To> cache(key: From, calculation: () -> S): S = inline fun <reified S : To> cache(key: From, calculation: () -> S): S =
cache.getOrPut(key, calculation) as S cache.getOrPut(key, calculation) as S
@@ -11,24 +11,20 @@ import org.jetbrains.kotlin.idea.frontend.api.assertIsValid
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
// all access are considered to be from a single thread /**
// which should be checked in invalidatable.assertIsValid() * Lazy value that guaranties safe publication and checks validity on every access
*/
class ValidityAwareCachedValue<T>( class ValidityAwareCachedValue<T>(
private val validityOwner: ValidityOwner, private val validityOwner: ValidityOwner,
private val init: () -> T init: () -> T
) : ReadOnlyProperty<Any, T> { ) : ReadOnlyProperty<Any, T> {
var value: Any? = UNITITIALIZED private val lazyValue = lazy(LazyThreadSafetyMode.PUBLICATION, init)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any, property: KProperty<*>): T { override fun getValue(thisRef: Any, property: KProperty<*>): T {
validityOwner.assertIsValid() validityOwner.assertIsValid()
if (value === UNITITIALIZED) { return lazyValue.value
value = init()
}
return value as T
} }
} }
internal fun <T> ValidityOwnerByValidityToken.cached(init: () -> T) = ValidityAwareCachedValue(token, init) internal fun <T> ValidityOwnerByValidityToken.cached(init: () -> T) = ValidityAwareCachedValue(token, init)
internal object UNITITIALIZED