diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt index 70979063fa9..cd2f537417a 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt @@ -39,7 +39,7 @@ class DeserializationComponentsForJava( init { val localClassResolver = LocalClassResolverImpl() - val settings = JvmBuiltInsSettings(moduleDescriptor, { moduleDescriptor }) + val settings = JvmBuiltInsSettings(moduleDescriptor, storageManager, { moduleDescriptor }) components = DeserializationComponents( storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, localClassResolver, errorReporter, lookupTracker, FlexibleJavaClassifierTypeFactory, ClassDescriptorFactory.EMPTY, diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt index 689b6af96a7..49e6cb41795 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.serialization.deserialization.PLATFORM_DEPENDENT_ANN import org.jetbrains.kotlin.serialization.deserialization.PlatformDependentDeclarationFilter import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.DelegatingType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.DFS @@ -49,6 +50,7 @@ import java.util.* open class JvmBuiltInsSettings( private val moduleDescriptor: ModuleDescriptor, + storageManager: StorageManager, deferredOwnerModuleDescriptor: () -> ModuleDescriptor ) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter { private val j2kClassMap = JavaToKotlinClassMap.INSTANCE @@ -57,6 +59,8 @@ open class JvmBuiltInsSettings( private val mockSerializableType = createMockJavaIoSerializableType() + private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues() + private fun createMockJavaIoSerializableType(): KotlinType { val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) { override fun getMemberScope() = MemberScope.Empty @@ -116,10 +120,11 @@ open class JvmBuiltInsSettings( val isMutable = j2kClassMap.isMutable(classDescriptor) - val fakeJavaClassDescriptor = - javaAnalogueDescriptor.copy( - javaResolverCache = JavaResolverCache.EMPTY, - additionalSupertypeClassDescriptor = kotlinMutableClassIfContainer) + val fakeJavaClassDescriptor = javaAnalogueClassesWithCustomSupertypeCache.computeIfAbsent(javaAnalogueDescriptor.fqNameSafe) { + javaAnalogueDescriptor.copy( + javaResolverCache = JavaResolverCache.EMPTY, + additionalSupertypeClassDescriptor = kotlinMutableClassIfContainer) + } val scope = fakeJavaClassDescriptor.unsubstitutedMemberScope diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt index 0bbf8c69bb3..d26c637170e 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt @@ -38,7 +38,7 @@ class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManage // Here we know order in which KotlinBuiltIns constructor calls these methods override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter { settings = JvmBuiltInsSettings( - builtInsModule, + builtInsModule, storageManager, { ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } } ) diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index fb054e925f3..f7c1dd5cddb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -61,7 +61,7 @@ public abstract class KotlinBuiltIns { BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("internal")) ); - protected final ModuleDescriptorImpl builtInsModule; + private final ModuleDescriptorImpl builtInsModule; private final PackageFragmentDescriptor builtInsPackageFragment; private final PackageFragmentDescriptor collectionsPackageFragment; private final PackageFragmentDescriptor rangesPackageFragment; @@ -72,10 +72,12 @@ public abstract class KotlinBuiltIns { private final Map primitiveTypeToArrayKotlinType; private final Map primitiveKotlinTypeToKotlinArrayType; private final Map kotlinArrayTypeToPrimitiveKotlinType; + private final StorageManager storageManager; public static final FqNames FQ_NAMES = new FqNames(); protected KotlinBuiltIns(@NotNull StorageManager storageManager) { + this.storageManager = storageManager; builtInsModule = new ModuleDescriptorImpl( Name.special(""), storageManager, ModuleParameters.Empty.INSTANCE, this ); @@ -144,6 +146,11 @@ public abstract class KotlinBuiltIns { return packageFragment; } + @NotNull + protected StorageManager getStorageManager() { + return storageManager; + } + @SuppressWarnings("WeakerAccess") public static class FqNames { public final FqNameUnsafe any = fqNameUnsafe("Any"); diff --git a/core/util.runtime/src/org/jetbrains/kotlin/storage/LockBasedStorageManager.java b/core/util.runtime/src/org/jetbrains/kotlin/storage/LockBasedStorageManager.java index 32a1b19e491..22626294197 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/storage/LockBasedStorageManager.java +++ b/core/util.runtime/src/org/jetbrains/kotlin/storage/LockBasedStorageManager.java @@ -501,4 +501,84 @@ public class LockBasedStorageManager implements StorageManager { throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()])); return throwable; } + + @NotNull + @Override + public CacheWithNullableValues createCacheWithNullableValues() { + return new CacheWithNullableValuesBasedOnMemoizedFunction( + this, LockBasedStorageManager.>createConcurrentHashMap()); + } + + private static class CacheWithNullableValuesBasedOnMemoizedFunction extends MapBasedMemoizedFunction, V> implements CacheWithNullableValues { + + private CacheWithNullableValuesBasedOnMemoizedFunction( + @NotNull LockBasedStorageManager storageManager, + @NotNull ConcurrentMap, Object> map + ) { + super(storageManager, map, new Function1, V>() { + @Override + public V invoke(KeyWithComputation computation) { + return computation.computation.invoke(); + } + }); + } + + @Nullable + @Override + public V computeIfAbsent(K key, @NotNull Function0 computation) { + return invoke(new KeyWithComputation(key, computation)); + } + } + + @NotNull + @Override + public CacheWithNotNullValues createCacheWithNotNullValues() { + return new CacheWithNotNullValuesBasedOnMemoizedFunction(this, LockBasedStorageManager.>createConcurrentHashMap()); + } + + private static class CacheWithNotNullValuesBasedOnMemoizedFunction extends CacheWithNullableValuesBasedOnMemoizedFunction implements CacheWithNotNullValues { + + private CacheWithNotNullValuesBasedOnMemoizedFunction( + @NotNull LockBasedStorageManager storageManager, + @NotNull ConcurrentMap, Object> map + ) { + super(storageManager, map); + } + + @NotNull + @Override + public V computeIfAbsent(K key, @NotNull Function0 computation) { + V result = super.computeIfAbsent(key, computation); + assert result != null : "computeIfAbsent() returned null under " + getStorageManager(); + return result; + } + } + + // equals and hashCode use only key + private static class KeyWithComputation { + private final K key; + private final Function0 computation; + + public KeyWithComputation(K key, Function0 computation) { + this.key = key; + this.computation = computation; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + KeyWithComputation that = (KeyWithComputation) o; + + if (!key.equals(that.key)) return false; + + return true; + } + + @Override + public int hashCode() { + return key.hashCode(); + } + } } diff --git a/core/util.runtime/src/org/jetbrains/kotlin/storage/ObservableStorageManager.kt b/core/util.runtime/src/org/jetbrains/kotlin/storage/ObservableStorageManager.kt index 34a3c3bf836..b8bd4d134b4 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/storage/ObservableStorageManager.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/storage/ObservableStorageManager.kt @@ -38,6 +38,14 @@ abstract class ObservableStorageManager(private val delegate: StorageManager) : return delegate.createMemoizedFunctionWithNullableValues(compute.observable, map) } + override fun createCacheWithNullableValues(): CacheWithNullableValues { + return delegate.createCacheWithNullableValues() + } + + override fun createCacheWithNotNullValues(): CacheWithNotNullValues { + return delegate.createCacheWithNotNullValues() + } + override fun createLazyValue(computable: () -> T): NotNullLazyValue { return delegate.createLazyValue(computable.observable) } diff --git a/core/util.runtime/src/org/jetbrains/kotlin/storage/StorageManager.kt b/core/util.runtime/src/org/jetbrains/kotlin/storage/StorageManager.kt index 56adfeda304..3c4de1d5f48 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/storage/StorageManager.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/storage/StorageManager.kt @@ -31,6 +31,9 @@ interface StorageManager { fun createMemoizedFunctionWithNullableValues(compute: (K) -> V?): MemoizedFunctionToNullable + fun createCacheWithNullableValues(): CacheWithNullableValues + fun createCacheWithNotNullValues(): CacheWithNotNullValues + fun createMemoizedFunction(compute: (K) -> V, map: ConcurrentMap): MemoizedFunctionToNotNull fun createMemoizedFunctionWithNullableValues(compute: (K) -> V, map: ConcurrentMap): MemoizedFunctionToNullable diff --git a/core/util.runtime/src/org/jetbrains/kotlin/storage/storage.kt b/core/util.runtime/src/org/jetbrains/kotlin/storage/storage.kt index 2c0c6750d34..596b14e22d6 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/storage/storage.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/storage/storage.kt @@ -39,3 +39,11 @@ interface NullableLazyValue : Function0 { operator fun NotNullLazyValue.getValue(_this: Any?, p: KProperty<*>): T = invoke() operator fun NullableLazyValue.getValue(_this: Any?, p: KProperty<*>): T? = invoke() + +interface CacheWithNullableValues { + fun computeIfAbsent(key: K, computation: () -> V?): V? +} + +interface CacheWithNotNullValues { + fun computeIfAbsent(key: K, computation: () -> V): V +}