Use cache for custom ClassDescriptors
Otherwise new ones are being created for each request, and their member scope is recomputed
This commit is contained in:
+1
-1
@@ -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,
|
||||
|
||||
+9
-4
@@ -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<FqName, ClassDescriptor>()
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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" } }
|
||||
)
|
||||
|
||||
|
||||
@@ -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<PrimitiveType, KotlinType> primitiveTypeToArrayKotlinType;
|
||||
private final Map<KotlinType, KotlinType> primitiveKotlinTypeToKotlinArrayType;
|
||||
private final Map<KotlinType, KotlinType> 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("<built-ins module>"), 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");
|
||||
|
||||
@@ -501,4 +501,84 @@ public class LockBasedStorageManager implements StorageManager {
|
||||
throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()]));
|
||||
return throwable;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <K, V> CacheWithNullableValues<K, V> createCacheWithNullableValues() {
|
||||
return new CacheWithNullableValuesBasedOnMemoizedFunction<K, V>(
|
||||
this, LockBasedStorageManager.<KeyWithComputation<K,V>>createConcurrentHashMap());
|
||||
}
|
||||
|
||||
private static class CacheWithNullableValuesBasedOnMemoizedFunction<K, V> extends MapBasedMemoizedFunction<KeyWithComputation<K, V>, V> implements CacheWithNullableValues<K, V> {
|
||||
|
||||
private CacheWithNullableValuesBasedOnMemoizedFunction(
|
||||
@NotNull LockBasedStorageManager storageManager,
|
||||
@NotNull ConcurrentMap<KeyWithComputation<K, V>, Object> map
|
||||
) {
|
||||
super(storageManager, map, new Function1<KeyWithComputation<K, V>, V>() {
|
||||
@Override
|
||||
public V invoke(KeyWithComputation<K, V> computation) {
|
||||
return computation.computation.invoke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V computeIfAbsent(K key, @NotNull Function0<? extends V> computation) {
|
||||
return invoke(new KeyWithComputation<K, V>(key, computation));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <K, V> CacheWithNotNullValues<K, V> createCacheWithNotNullValues() {
|
||||
return new CacheWithNotNullValuesBasedOnMemoizedFunction<K, V>(this, LockBasedStorageManager.<KeyWithComputation<K,V>>createConcurrentHashMap());
|
||||
}
|
||||
|
||||
private static class CacheWithNotNullValuesBasedOnMemoizedFunction<K, V> extends CacheWithNullableValuesBasedOnMemoizedFunction<K, V> implements CacheWithNotNullValues<K, V> {
|
||||
|
||||
private CacheWithNotNullValuesBasedOnMemoizedFunction(
|
||||
@NotNull LockBasedStorageManager storageManager,
|
||||
@NotNull ConcurrentMap<KeyWithComputation<K, V>, Object> map
|
||||
) {
|
||||
super(storageManager, map);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public V computeIfAbsent(K key, @NotNull Function0<? extends V> 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<K, V> {
|
||||
private final K key;
|
||||
private final Function0<? extends V> computation;
|
||||
|
||||
public KeyWithComputation(K key, Function0<? extends V> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@ abstract class ObservableStorageManager(private val delegate: StorageManager) :
|
||||
return delegate.createMemoizedFunctionWithNullableValues(compute.observable, map)
|
||||
}
|
||||
|
||||
override fun <K, V : Any> createCacheWithNullableValues(): CacheWithNullableValues<K, V> {
|
||||
return delegate.createCacheWithNullableValues()
|
||||
}
|
||||
|
||||
override fun <K, V : Any> createCacheWithNotNullValues(): CacheWithNotNullValues<K, V> {
|
||||
return delegate.createCacheWithNotNullValues()
|
||||
}
|
||||
|
||||
override fun <T: Any> createLazyValue(computable: () -> T): NotNullLazyValue<T> {
|
||||
return delegate.createLazyValue(computable.observable)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ interface StorageManager {
|
||||
|
||||
fun <K, V : Any> createMemoizedFunctionWithNullableValues(compute: (K) -> V?): MemoizedFunctionToNullable<K, V>
|
||||
|
||||
fun <K, V : Any> createCacheWithNullableValues(): CacheWithNullableValues<K, V>
|
||||
fun <K, V : Any> createCacheWithNotNullValues(): CacheWithNotNullValues<K, V>
|
||||
|
||||
fun <K, V : Any> createMemoizedFunction(compute: (K) -> V, map: ConcurrentMap<K, Any>): MemoizedFunctionToNotNull<K, V>
|
||||
|
||||
fun <K, V : Any> createMemoizedFunctionWithNullableValues(compute: (K) -> V, map: ConcurrentMap<K, Any>): MemoizedFunctionToNullable<K, V>
|
||||
|
||||
@@ -39,3 +39,11 @@ interface NullableLazyValue<T : Any> : Function0<T?> {
|
||||
operator fun <T : Any> NotNullLazyValue<T>.getValue(_this: Any?, p: KProperty<*>): T = invoke()
|
||||
|
||||
operator fun <T : Any> NullableLazyValue<T>.getValue(_this: Any?, p: KProperty<*>): T? = invoke()
|
||||
|
||||
interface CacheWithNullableValues<in K, V : Any> {
|
||||
fun computeIfAbsent(key: K, computation: () -> V?): V?
|
||||
}
|
||||
|
||||
interface CacheWithNotNullValues<in K, V : Any> {
|
||||
fun computeIfAbsent(key: K, computation: () -> V): V
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user