Avoid retaining all protobuf objects in DeserializedMemberScope
Object model for deserialized protobuf isn't very cheap, so loading just our stdlib's packages several times (as we do in the IDE) might lead to ~ 96 MB of retained memory just by these objects. While in fact many of them remain unused #KT-21517 Fixed
This commit is contained in:
+2
-1
@@ -53,7 +53,8 @@ class JvmBuiltInsPackageFragmentProvider(
|
|||||||
),
|
),
|
||||||
notFoundClasses,
|
notFoundClasses,
|
||||||
ContractDeserializer.DEFAULT,
|
ContractDeserializer.DEFAULT,
|
||||||
additionalClassPartsProvider, platformDependentDeclarationFilter
|
additionalClassPartsProvider, platformDependentDeclarationFilter,
|
||||||
|
BuiltInSerializerProtocol.extensionRegistry
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
|||||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
||||||
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
|
|
||||||
// This class is needed only for easier injection: exact types of needed components are specified in the constructor here.
|
// This class is needed only for easier injection: exact types of needed components are specified in the constructor here.
|
||||||
@@ -50,7 +51,8 @@ class DeserializationComponentsForJava(
|
|||||||
LocalClassifierTypeSettings.Default, errorReporter, lookupTracker, JavaFlexibleTypeDeserializer,
|
LocalClassifierTypeSettings.Default, errorReporter, lookupTracker, JavaFlexibleTypeDeserializer,
|
||||||
emptyList(), notFoundClasses, contractDeserializer,
|
emptyList(), notFoundClasses, contractDeserializer,
|
||||||
additionalClassPartsProvider = jvmBuiltIns?.settings ?: AdditionalClassPartsProvider.None,
|
additionalClassPartsProvider = jvmBuiltIns?.settings ?: AdditionalClassPartsProvider.None,
|
||||||
platformDependentDeclarationFilter = jvmBuiltIns?.settings ?: PlatformDependentDeclarationFilter.NoPlatformDependent
|
platformDependentDeclarationFilter = jvmBuiltIns?.settings ?: PlatformDependentDeclarationFilter.NoPlatformDependent,
|
||||||
|
extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ class BuiltInsLoaderImpl : BuiltInsLoader {
|
|||||||
notFoundClasses,
|
notFoundClasses,
|
||||||
ContractDeserializer.DEFAULT,
|
ContractDeserializer.DEFAULT,
|
||||||
additionalClassPartsProvider,
|
additionalClassPartsProvider,
|
||||||
platformDependentDeclarationFilter
|
platformDependentDeclarationFilter,
|
||||||
|
BuiltInSerializerProtocol.extensionRegistry
|
||||||
)
|
)
|
||||||
|
|
||||||
for (packageFragment in packageFragments) {
|
for (packageFragment in packageFragments) {
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
|||||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
||||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -60,7 +59,8 @@ class MetadataPackageFragmentProvider(
|
|||||||
emptyList(),
|
emptyList(),
|
||||||
notFoundClasses,
|
notFoundClasses,
|
||||||
ContractDeserializer.DEFAULT,
|
ContractDeserializer.DEFAULT,
|
||||||
AdditionalClassPartsProvider.None, PlatformDependentDeclarationFilter.All
|
AdditionalClassPartsProvider.None, PlatformDependentDeclarationFilter.All,
|
||||||
|
BuiltInSerializerProtocol.extensionRegistry
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.deserialization.ClassDescriptorFactory
|
|||||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||||
@@ -45,7 +46,8 @@ class DeserializationComponents(
|
|||||||
val notFoundClasses: NotFoundClasses,
|
val notFoundClasses: NotFoundClasses,
|
||||||
val contractDeserializer: ContractDeserializer,
|
val contractDeserializer: ContractDeserializer,
|
||||||
val additionalClassPartsProvider: AdditionalClassPartsProvider = AdditionalClassPartsProvider.None,
|
val additionalClassPartsProvider: AdditionalClassPartsProvider = AdditionalClassPartsProvider.None,
|
||||||
val platformDependentDeclarationFilter: PlatformDependentDeclarationFilter = PlatformDependentDeclarationFilter.All
|
val platformDependentDeclarationFilter: PlatformDependentDeclarationFilter = PlatformDependentDeclarationFilter.All,
|
||||||
|
val extensionRegistryLite: ExtensionRegistryLite
|
||||||
) {
|
) {
|
||||||
val classDeserializer: ClassDeserializer = ClassDeserializer(this)
|
val classDeserializer: ClassDeserializer = ClassDeserializer(this)
|
||||||
|
|
||||||
|
|||||||
+64
-40
@@ -20,7 +20,9 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.protobuf.AbstractMessageLite
|
||||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||||
|
import org.jetbrains.kotlin.protobuf.Parser
|
||||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||||
@@ -30,6 +32,8 @@ import org.jetbrains.kotlin.storage.getValue
|
|||||||
import org.jetbrains.kotlin.utils.Printer
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.compact
|
import org.jetbrains.kotlin.utils.compact
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class DeserializedMemberScope protected constructor(
|
abstract class DeserializedMemberScope protected constructor(
|
||||||
@@ -40,20 +44,22 @@ abstract class DeserializedMemberScope protected constructor(
|
|||||||
classNames: () -> Collection<Name>
|
classNames: () -> Collection<Name>
|
||||||
) : MemberScopeImpl() {
|
) : MemberScopeImpl() {
|
||||||
|
|
||||||
private val functionProtos by
|
private val functionProtosBytes = functionList.groupByName { it.name }.packToByteArray()
|
||||||
c.storageManager.createLazyValue {
|
|
||||||
functionList.groupByName { it.name }
|
private val propertyProtosBytes = propertyList.groupByName { it.name }.packToByteArray()
|
||||||
}
|
|
||||||
private val propertyProtos by
|
private val typeAliasBytes =
|
||||||
c.storageManager.createLazyValue {
|
if (c.components.configuration.typeAliasesAllowed)
|
||||||
propertyList.groupByName { it.name }
|
typeAliasList.groupByName { it.name }.packToByteArray()
|
||||||
}
|
else
|
||||||
private val typeAliasProtos by
|
emptyMap()
|
||||||
c.storageManager.createLazyValue {
|
|
||||||
if (c.components.configuration.typeAliasesAllowed)
|
private fun Map<Name, Collection<AbstractMessageLite>>.packToByteArray(): Map<Name, ByteArray> =
|
||||||
typeAliasList.groupByName { it.name }
|
mapValues { entry ->
|
||||||
else emptyMap()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
}
|
entry.value.map { proto -> proto.writeDelimitedTo(byteArrayOutputStream) }
|
||||||
|
byteArrayOutputStream.toByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
private val functions =
|
private val functions =
|
||||||
c.storageManager.createMemoizedFunction<Name, Collection<SimpleFunctionDescriptor>> { computeFunctions(it) }
|
c.storageManager.createMemoizedFunction<Name, Collection<SimpleFunctionDescriptor>> { computeFunctions(it) }
|
||||||
@@ -63,14 +69,14 @@ abstract class DeserializedMemberScope protected constructor(
|
|||||||
c.storageManager.createMemoizedFunctionWithNullableValues<Name, TypeAliasDescriptor> { createTypeAlias(it) }
|
c.storageManager.createMemoizedFunctionWithNullableValues<Name, TypeAliasDescriptor> { createTypeAlias(it) }
|
||||||
|
|
||||||
private val functionNamesLazy by c.storageManager.createLazyValue {
|
private val functionNamesLazy by c.storageManager.createLazyValue {
|
||||||
functionProtos.keys + getNonDeclaredFunctionNames()
|
functionProtosBytes.keys + getNonDeclaredFunctionNames()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val variableNamesLazy by c.storageManager.createLazyValue {
|
private val variableNamesLazy by c.storageManager.createLazyValue {
|
||||||
propertyProtos.keys + getNonDeclaredVariableNames()
|
propertyProtosBytes.keys + getNonDeclaredVariableNames()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val typeAliasNames: Set<Name> get() = typeAliasProtos.keys
|
private val typeAliasNames: Set<Name> get() = typeAliasBytes.keys
|
||||||
|
|
||||||
internal val classNames by c.storageManager.createLazyValue { classNames().toSet() }
|
internal val classNames by c.storageManager.createLazyValue { classNames().toSet() }
|
||||||
|
|
||||||
@@ -87,21 +93,37 @@ abstract class DeserializedMemberScope protected constructor(
|
|||||||
) = groupBy { c.nameResolver.getName(getNameIndex(it)) }
|
) = groupBy { c.nameResolver.getName(getNameIndex(it)) }
|
||||||
|
|
||||||
private fun computeFunctions(name: Name) =
|
private fun computeFunctions(name: Name) =
|
||||||
computeDescriptors(
|
computeDescriptors(
|
||||||
name,
|
name,
|
||||||
functionProtos,
|
functionProtosBytes,
|
||||||
{ c.memberDeserializer.loadFunction(it) },
|
ProtoBuf.Function.PARSER,
|
||||||
{ computeNonDeclaredFunctions(name, it)}
|
{ c.memberDeserializer.loadFunction(it) },
|
||||||
)
|
{ computeNonDeclaredFunctions(name, it) }
|
||||||
|
)
|
||||||
|
|
||||||
inline private fun <M : MessageLite, D : DeclarationDescriptor> computeDescriptors(
|
private inline fun <M : MessageLite, D : DeclarationDescriptor> computeDescriptors(
|
||||||
name: Name,
|
name: Name,
|
||||||
protosByName: Map<Name, Collection<M>>,
|
bytesByName: Map<Name, ByteArray>,
|
||||||
factory: (M) -> D,
|
parser: Parser<M>,
|
||||||
computeNonDeclared: (MutableCollection<D>) -> Unit
|
factory: (M) -> D,
|
||||||
|
computeNonDeclared: (MutableCollection<D>) -> Unit
|
||||||
|
): Collection<D> =
|
||||||
|
computeDescriptors(
|
||||||
|
bytesByName[name]?.let {
|
||||||
|
val inputStream = ByteArrayInputStream(it)
|
||||||
|
generateSequence {
|
||||||
|
parser.parseDelimitedFrom(inputStream, c.components.extensionRegistryLite)
|
||||||
|
}.toList()
|
||||||
|
} ?: emptyList(),
|
||||||
|
factory,
|
||||||
|
computeNonDeclared
|
||||||
|
)
|
||||||
|
|
||||||
|
private inline fun <M : MessageLite, D : DeclarationDescriptor> computeDescriptors(
|
||||||
|
protos: Collection<M>,
|
||||||
|
factory: (M) -> D,
|
||||||
|
computeNonDeclared: (MutableCollection<D>) -> Unit
|
||||||
): Collection<D> {
|
): Collection<D> {
|
||||||
val protos = protosByName[name].orEmpty()
|
|
||||||
|
|
||||||
val descriptors = protos.mapTo(arrayListOf(), factory)
|
val descriptors = protos.mapTo(arrayListOf(), factory)
|
||||||
|
|
||||||
computeNonDeclared(descriptors)
|
computeNonDeclared(descriptors)
|
||||||
@@ -117,20 +139,22 @@ abstract class DeserializedMemberScope protected constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun computeProperties(name: Name) =
|
private fun computeProperties(name: Name) =
|
||||||
computeDescriptors(
|
computeDescriptors(
|
||||||
name,
|
name,
|
||||||
propertyProtos,
|
propertyProtosBytes,
|
||||||
{ c.memberDeserializer.loadProperty(it) },
|
ProtoBuf.Property.PARSER,
|
||||||
{ computeNonDeclaredProperties(name, it) }
|
{ c.memberDeserializer.loadProperty(it) },
|
||||||
)
|
{ computeNonDeclaredProperties(name, it) }
|
||||||
|
)
|
||||||
|
|
||||||
protected open fun computeNonDeclaredProperties(name: Name, descriptors: MutableCollection<PropertyDescriptor>) {
|
protected open fun computeNonDeclaredProperties(name: Name, descriptors: MutableCollection<PropertyDescriptor>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTypeAlias(name: Name) =
|
private fun createTypeAlias(name: Name): TypeAliasDescriptor? {
|
||||||
typeAliasProtos[name]?.singleOrNull()?.let {
|
val byteArray = typeAliasBytes[name] ?: return null
|
||||||
c.memberDeserializer.loadTypeAlias(it)
|
val proto = ProtoBuf.TypeAlias.parseDelimitedFrom(ByteArrayInputStream(byteArray)) ?: return null
|
||||||
}
|
return c.memberDeserializer.loadTypeAlias(proto)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||||
if (name !in getVariableNames()) return emptyList()
|
if (name !in getVariableNames()) return emptyList()
|
||||||
|
|||||||
+2
-1
@@ -71,7 +71,8 @@ class DeserializerForClassfileDecompiler(
|
|||||||
storageManager, moduleDescriptor, DeserializationConfiguration.Default, classDataFinder, annotationAndConstantLoader,
|
storageManager, moduleDescriptor, DeserializationConfiguration.Default, classDataFinder, annotationAndConstantLoader,
|
||||||
packageFragmentProvider, ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
packageFragmentProvider, ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
||||||
LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses,
|
LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses,
|
||||||
ContractDeserializer.DEFAULT
|
ContractDeserializer.DEFAULT,
|
||||||
|
extensionRegistryLite = JvmProtoBufUtil.EXTENSION_REGISTRY
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -52,7 +52,8 @@ class KotlinMetadataDeserializerForDecompiler(
|
|||||||
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, serializerProtocol), packageFragmentProvider,
|
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, serializerProtocol), packageFragmentProvider,
|
||||||
ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
||||||
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses,
|
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses,
|
||||||
ContractDeserializer.DEFAULT
|
ContractDeserializer.DEFAULT,
|
||||||
|
extensionRegistryLite = serializerProtocol.extensionRegistry
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -73,7 +73,8 @@ fun createKotlinJavascriptPackageFragmentProvider(
|
|||||||
emptyList(),
|
emptyList(),
|
||||||
notFoundClasses,
|
notFoundClasses,
|
||||||
ContractDeserializerImpl(configuration),
|
ContractDeserializerImpl(configuration),
|
||||||
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent
|
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent,
|
||||||
|
extensionRegistryLite = JsSerializerProtocol.extensionRegistry
|
||||||
)
|
)
|
||||||
|
|
||||||
for (packageFragment in packageFragments.filterIsInstance<KotlinJavascriptPackageFragment>()) {
|
for (packageFragment in packageFragments.filterIsInstance<KotlinJavascriptPackageFragment>()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user