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:
Denis Zharkov
2016-05-04 10:18:04 +03:00
parent 594fa02a9c
commit c30c695a18
8 changed files with 118 additions and 7 deletions
@@ -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,
@@ -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
}