ModuleDescriptor: invert "friends" relation

Fixes memory leak caused by modules storing their friends (which can be potentially recreated many times)
This commit is contained in:
Pavel V. Talanov
2016-09-15 16:03:08 +03:00
parent 23c0bdbd05
commit 8f5725345f
5 changed files with 34 additions and 37 deletions
@@ -169,37 +169,33 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
fun computeDependencyDescriptors(module: M): List<ModuleDescriptorImpl> {
val orderedDependencies = firstDependency.singletonOrEmptyList() + module.dependencies()
val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) {
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<ModuleDescriptorImpl> {
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 ->
@@ -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
@@ -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);
}
@@ -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<ModuleDescriptorImpl>) {
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<ModuleDescriptor>()
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 <T> getCapability(capability: ModuleDescriptor.Capability<T>) = capabilities[capability] as? T
}
interface ModuleDependencies {
val descriptors: List<ModuleDescriptorImpl>
val allDependencies: List<ModuleDescriptorImpl>
val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
}
class ModuleDependenciesImpl(override val descriptors: List<ModuleDescriptorImpl>) : ModuleDependencies
class ModuleDependenciesImpl(
override val allDependencies: List<ModuleDescriptorImpl>,
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
) : ModuleDependencies
class LazyModuleDependencies(
storageManager: StorageManager,
computeDependencies: () -> List<ModuleDescriptorImpl>
computeDependencies: () -> List<ModuleDescriptorImpl>,
computeModulesWhoseInternalsAreVisible: () -> Set<ModuleDescriptorImpl>
) : ModuleDependencies {
private val dependencies = storageManager.createLazyValue(computeDependencies)
private val visibleInternals = storageManager.createLazyValue(computeModulesWhoseInternalsAreVisible)
override val descriptors: List<ModuleDescriptorImpl>
get() = dependencies()
override val allDependencies: List<ModuleDescriptorImpl> get() = dependencies()
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl> get() = visibleInternals()
}
@@ -118,7 +118,7 @@ public class ErrorUtils {
}
@Override
public boolean isFriend(@NotNull ModuleDescriptor other) {
public boolean shouldSeeInternalsOf(@NotNull ModuleDescriptor targetModule) {
return false;
}