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 {
|
init {
|
||||||
val localClassResolver = LocalClassResolverImpl()
|
val localClassResolver = LocalClassResolverImpl()
|
||||||
val settings = JvmBuiltInsSettings(moduleDescriptor, { moduleDescriptor })
|
val settings = JvmBuiltInsSettings(moduleDescriptor, storageManager, { moduleDescriptor })
|
||||||
components = DeserializationComponents(
|
components = DeserializationComponents(
|
||||||
storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, localClassResolver,
|
storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, localClassResolver,
|
||||||
errorReporter, lookupTracker, FlexibleJavaClassifierTypeFactory, ClassDescriptorFactory.EMPTY,
|
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.PlatformDependentDeclarationFilter
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import org.jetbrains.kotlin.types.DelegatingType
|
import org.jetbrains.kotlin.types.DelegatingType
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
@@ -49,6 +50,7 @@ import java.util.*
|
|||||||
|
|
||||||
open class JvmBuiltInsSettings(
|
open class JvmBuiltInsSettings(
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
|
storageManager: StorageManager,
|
||||||
deferredOwnerModuleDescriptor: () -> ModuleDescriptor
|
deferredOwnerModuleDescriptor: () -> ModuleDescriptor
|
||||||
) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter {
|
) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter {
|
||||||
private val j2kClassMap = JavaToKotlinClassMap.INSTANCE
|
private val j2kClassMap = JavaToKotlinClassMap.INSTANCE
|
||||||
@@ -57,6 +59,8 @@ open class JvmBuiltInsSettings(
|
|||||||
|
|
||||||
private val mockSerializableType = createMockJavaIoSerializableType()
|
private val mockSerializableType = createMockJavaIoSerializableType()
|
||||||
|
|
||||||
|
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
|
||||||
|
|
||||||
private fun createMockJavaIoSerializableType(): KotlinType {
|
private fun createMockJavaIoSerializableType(): KotlinType {
|
||||||
val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) {
|
val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) {
|
||||||
override fun getMemberScope() = MemberScope.Empty
|
override fun getMemberScope() = MemberScope.Empty
|
||||||
@@ -116,10 +120,11 @@ open class JvmBuiltInsSettings(
|
|||||||
|
|
||||||
val isMutable = j2kClassMap.isMutable(classDescriptor)
|
val isMutable = j2kClassMap.isMutable(classDescriptor)
|
||||||
|
|
||||||
val fakeJavaClassDescriptor =
|
val fakeJavaClassDescriptor = javaAnalogueClassesWithCustomSupertypeCache.computeIfAbsent(javaAnalogueDescriptor.fqNameSafe) {
|
||||||
javaAnalogueDescriptor.copy(
|
javaAnalogueDescriptor.copy(
|
||||||
javaResolverCache = JavaResolverCache.EMPTY,
|
javaResolverCache = JavaResolverCache.EMPTY,
|
||||||
additionalSupertypeClassDescriptor = kotlinMutableClassIfContainer)
|
additionalSupertypeClassDescriptor = kotlinMutableClassIfContainer)
|
||||||
|
}
|
||||||
|
|
||||||
val scope = fakeJavaClassDescriptor.unsubstitutedMemberScope
|
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
|
// Here we know order in which KotlinBuiltIns constructor calls these methods
|
||||||
override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter {
|
override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter {
|
||||||
settings = JvmBuiltInsSettings(
|
settings = JvmBuiltInsSettings(
|
||||||
builtInsModule,
|
builtInsModule, storageManager,
|
||||||
{ ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } }
|
{ 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"))
|
BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("internal"))
|
||||||
);
|
);
|
||||||
|
|
||||||
protected final ModuleDescriptorImpl builtInsModule;
|
private final ModuleDescriptorImpl builtInsModule;
|
||||||
private final PackageFragmentDescriptor builtInsPackageFragment;
|
private final PackageFragmentDescriptor builtInsPackageFragment;
|
||||||
private final PackageFragmentDescriptor collectionsPackageFragment;
|
private final PackageFragmentDescriptor collectionsPackageFragment;
|
||||||
private final PackageFragmentDescriptor rangesPackageFragment;
|
private final PackageFragmentDescriptor rangesPackageFragment;
|
||||||
@@ -72,10 +72,12 @@ public abstract class KotlinBuiltIns {
|
|||||||
private final Map<PrimitiveType, KotlinType> primitiveTypeToArrayKotlinType;
|
private final Map<PrimitiveType, KotlinType> primitiveTypeToArrayKotlinType;
|
||||||
private final Map<KotlinType, KotlinType> primitiveKotlinTypeToKotlinArrayType;
|
private final Map<KotlinType, KotlinType> primitiveKotlinTypeToKotlinArrayType;
|
||||||
private final Map<KotlinType, KotlinType> kotlinArrayTypeToPrimitiveKotlinType;
|
private final Map<KotlinType, KotlinType> kotlinArrayTypeToPrimitiveKotlinType;
|
||||||
|
private final StorageManager storageManager;
|
||||||
|
|
||||||
public static final FqNames FQ_NAMES = new FqNames();
|
public static final FqNames FQ_NAMES = new FqNames();
|
||||||
|
|
||||||
protected KotlinBuiltIns(@NotNull StorageManager storageManager) {
|
protected KotlinBuiltIns(@NotNull StorageManager storageManager) {
|
||||||
|
this.storageManager = storageManager;
|
||||||
builtInsModule = new ModuleDescriptorImpl(
|
builtInsModule = new ModuleDescriptorImpl(
|
||||||
Name.special("<built-ins module>"), storageManager, ModuleParameters.Empty.INSTANCE, this
|
Name.special("<built-ins module>"), storageManager, ModuleParameters.Empty.INSTANCE, this
|
||||||
);
|
);
|
||||||
@@ -144,6 +146,11 @@ public abstract class KotlinBuiltIns {
|
|||||||
return packageFragment;
|
return packageFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected StorageManager getStorageManager() {
|
||||||
|
return storageManager;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public static class FqNames {
|
public static class FqNames {
|
||||||
public final FqNameUnsafe any = fqNameUnsafe("Any");
|
public final FqNameUnsafe any = fqNameUnsafe("Any");
|
||||||
|
|||||||
@@ -501,4 +501,84 @@ public class LockBasedStorageManager implements StorageManager {
|
|||||||
throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()]));
|
throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()]));
|
||||||
return throwable;
|
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)
|
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> {
|
override fun <T: Any> createLazyValue(computable: () -> T): NotNullLazyValue<T> {
|
||||||
return delegate.createLazyValue(computable.observable)
|
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> 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> 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>
|
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> NotNullLazyValue<T>.getValue(_this: Any?, p: KProperty<*>): T = invoke()
|
||||||
|
|
||||||
operator fun <T : Any> NullableLazyValue<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