From 8f5725345fd3f53feefb08d21b0b96f0cdcd2e2e Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 15 Sep 2016 16:03:08 +0300 Subject: [PATCH] ModuleDescriptor: invert "friends" relation Fixes memory leak caused by modules storing their friends (which can be potentially recreated many times) --- .../kotlin/analyzer/AnalyzerFacade.kt | 28 ++++++-------- .../kotlin/descriptors/ModuleDescriptor.kt | 2 +- .../kotlin/descriptors/Visibilities.java | 2 +- .../descriptors/impl/ModuleDescriptorImpl.kt | 37 ++++++++++--------- .../jetbrains/kotlin/types/ErrorUtils.java | 2 +- 5 files changed, 34 insertions(+), 37 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt index 6a62562332e..7a321620e84 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt @@ -169,37 +169,33 @@ abstract class AnalyzerFacade { fun computeDependencyDescriptors(module: M): List { val orderedDependencies = firstDependency.singletonOrEmptyList() + module.dependencies() val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList()) { - dependencyInfo -> - resolverForProject.descriptorForModule(dependencyInfo as M) - } + dependencyInfo -> + resolverForProject.descriptorForModule(dependencyInfo as M) + } module.dependencyOnBuiltIns().adjustDependencies( resolverForProject.descriptorForModule(module).builtIns.builtInsModule, dependenciesDescriptors) return dependenciesDescriptors } + fun computeModulesWhoseInternalsAreVisible(module: M): Set { + return module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) { resolverForProject.descriptorForModule(it as M) } + } + fun setupModuleDependencies() { modules.forEach { module -> resolverForProject.descriptorForModule(module).setDependencies( - LazyModuleDependencies(storageManager) { computeDependencyDescriptors(module) } + LazyModuleDependencies( + storageManager, + { computeDependencyDescriptors(module) }, + { computeModulesWhoseInternalsAreVisible(module) } + ) ) } } setupModuleDependencies() - fun addFriends() { - modules.forEach { - module -> - val descriptor = resolverForProject.descriptorForModule(module) - module.modulesWhoseInternalsAreVisible().forEach { - resolverForProject.descriptorForModule(it as M).addFriend(descriptor) - } - } - } - - addFriends() - fun initializeResolverForProject() { modules.forEach { module -> diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt index eca88077d00..2866a1b54a7 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ModuleDescriptor.kt @@ -28,7 +28,7 @@ interface ModuleDescriptor : DeclarationDescriptor, ModuleParameters { val builtIns: KotlinBuiltIns - fun isFriend(other: ModuleDescriptor): Boolean + fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean override fun substitute(substitutor: TypeSubstitutor): ModuleDescriptor { return this diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/Visibilities.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/Visibilities.java index f3fb2c338f8..546bfb28d0a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/Visibilities.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/Visibilities.java @@ -207,7 +207,7 @@ public class Visibilities { @Override public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) { DeclarationDescriptor fromOrModule = from instanceof PackageViewDescriptor ? ((PackageViewDescriptor) from).getModule() : from; - if (!DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(fromOrModule))) return false; + if (!DescriptorUtils.getContainingModule(fromOrModule).shouldSeeInternalsOf(DescriptorUtils.getContainingModule(what))) return false; return MODULE_VISIBILITY_HELPER.isInFriendModule(what, from); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt index 0e2a0360b02..f93ce96e0b1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/ModuleDescriptorImpl.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.sure -import java.util.* +import java.lang.IllegalArgumentException class ModuleDescriptorImpl @JvmOverloads constructor( moduleName: Name, @@ -56,8 +56,8 @@ class ModuleDescriptorImpl @JvmOverloads constructor( private val packageFragmentProviderForWholeModuleWithDependencies by lazy { val moduleDependencies = dependencies.sure { "Dependencies of module $id were not set before querying module content" } - val dependenciesDescriptors = moduleDependencies.descriptors - assert(this in dependenciesDescriptors) { "Module ${id} is not contained in his own dependencies, this is probably a misconfiguration" } + val dependenciesDescriptors = moduleDependencies.allDependencies + assert(this in dependenciesDescriptors) { "Module $id is not contained in his own dependencies, this is probably a misconfiguration" } dependenciesDescriptors.forEach { dependency -> assert(dependency.isInitialized) { @@ -82,7 +82,11 @@ class ModuleDescriptorImpl @JvmOverloads constructor( } fun setDependencies(descriptors: List) { - setDependencies(ModuleDependenciesImpl(descriptors)) + setDependencies(ModuleDependenciesImpl(descriptors, emptySet())) + } + + override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean { + return this == targetModule || targetModule in dependencies!!.modulesWhoseInternalsAreVisible } private val id: String @@ -99,31 +103,28 @@ class ModuleDescriptorImpl @JvmOverloads constructor( val packageFragmentProvider: PackageFragmentProvider get() = packageFragmentProviderForWholeModuleWithDependencies - private val friendModules = LinkedHashSet() - - override fun isFriend(other: ModuleDescriptor) = other == this || other in friendModules - - fun addFriend(friend: ModuleDescriptorImpl): Unit { - assert(friend != this) { "Attempt to make module $id a friend to itself" } - friendModules.add(friend) - } - @Suppress("UNCHECKED_CAST") override fun getCapability(capability: ModuleDescriptor.Capability) = capabilities[capability] as? T } interface ModuleDependencies { - val descriptors: List + val allDependencies: List + val modulesWhoseInternalsAreVisible: Set } -class ModuleDependenciesImpl(override val descriptors: List) : ModuleDependencies +class ModuleDependenciesImpl( + override val allDependencies: List, + override val modulesWhoseInternalsAreVisible: Set +) : ModuleDependencies class LazyModuleDependencies( storageManager: StorageManager, - computeDependencies: () -> List + computeDependencies: () -> List, + computeModulesWhoseInternalsAreVisible: () -> Set ) : ModuleDependencies { private val dependencies = storageManager.createLazyValue(computeDependencies) + private val visibleInternals = storageManager.createLazyValue(computeModulesWhoseInternalsAreVisible) - override val descriptors: List - get() = dependencies() + override val allDependencies: List get() = dependencies() + override val modulesWhoseInternalsAreVisible: Set get() = visibleInternals() } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 76615627a4e..2070cd56348 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -118,7 +118,7 @@ public class ErrorUtils { } @Override - public boolean isFriend(@NotNull ModuleDescriptor other) { + public boolean shouldSeeInternalsOf(@NotNull ModuleDescriptor targetModule) { return false; }