Memory optimization
diff --git a/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/decompiler/KotlinNativeLoadingMetadataCache.kt b/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/decompiler/KotlinNativeLoadingMetadataCache.kt
index 7faccd8..fd10c9e 100644
--- a/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/decompiler/KotlinNativeLoadingMetadataCache.kt
+++ b/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/decompiler/KotlinNativeLoadingMetadataCache.kt
@@ -9,6 +9,7 @@
import com.intellij.openapi.components.ApplicationComponent
import com.intellij.openapi.vfs.*
import com.intellij.util.containers.ContainerUtil.createConcurrentSoftValueMap
+import com.intellij.util.containers.ContainerUtil.createConcurrentWeakValueMap
import org.jetbrains.kotlin.konan.library.KLIB_METADATA_FILE_EXTENSION
import org.jetbrains.kotlin.konan.library.KLIB_MODULE_METADATA_FILE_NAME
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
@@ -23,7 +24,7 @@
ApplicationManager.getApplication().getComponent(KotlinNativeLoadingMetadataCache::class.java)
}
- private val packageFragmentCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataPackageFragment>()
+ private val packageFragmentCache = createConcurrentWeakValueMap<VirtualFile, KonanProtoBuf.LinkDataPackageFragment>()
private val moduleHeaderCache = createConcurrentSoftValueMap<VirtualFile, KonanProtoBuf.LinkDataLibrary>()
fun getCachedPackageFragment(virtualFile: VirtualFile): KonanProtoBuf.LinkDataPackageFragment =
diff --git a/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanClassDataFinder.kt b/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanClassDataFinder.kt
index e86679c..d9b71c8 100644
--- a/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanClassDataFinder.kt
+++ b/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanClassDataFinder.kt
@@ -33,3 +33,21 @@
return ClassData(nameResolver, foundClass, KonanMetadataVersion.INSTANCE, SourceElement.NO_SOURCE)
}
}
+
+class KotlinNativeProtoBasedClassDataFinder(
+ proto: KonanProtoBuf.LinkDataPackageFragment,
+ private val nameResolver: NameResolver,
+ private val classSource: (ClassId) -> SourceElement = { SourceElement.NO_SOURCE }
+) : ClassDataFinder {
+ private val classIdToProto =
+ proto.classes.classesList.associateBy { klass ->
+ nameResolver.getClassId(klass.fqName)
+ }
+
+ internal val allClassIds: Collection<ClassId> get() = classIdToProto.keys
+
+ override fun findClassData(classId: ClassId): ClassData? {
+ val classProto = classIdToProto[classId] ?: return null
+ return ClassData(nameResolver, classProto, KonanMetadataVersion.INSTANCE, classSource(classId))
+ }
+}
diff --git a/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanPackageFragment.kt b/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanPackageFragment.kt
index 6e332f5..eba2c56 100644
--- a/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanPackageFragment.kt
+++ b/konan/library-reader/src/org/jetbrains/kotlin/serialization/konan/KonanPackageFragment.kt
@@ -25,7 +25,7 @@
private val packageAccessedHandler: PackageAccessedHandler?,
storageManager: StorageManager,
module: ModuleDescriptor,
- partName: String
+ val partName: String
) : DeserializedPackageFragment(fqName, storageManager, module) {
lateinit var components: DeserializationComponents
@@ -36,7 +36,11 @@
// The proto field is lazy so that we can load only needed
// packages from the library.
- private val protoForNames: KonanProtoBuf.LinkDataPackageFragment by lazy { library.packageMetadata(fqName.asString(), partName) }
+ private val protoForNames: KonanProtoBuf.LinkDataPackageFragment
+ get() =
+ protoForNamesStore ?: library.packageMetadata(fqName.asString(), partName).also { protoForNamesStore = it }
+
+ private var protoForNamesStore: KonanProtoBuf.LinkDataPackageFragment? = null
val proto: KonanProtoBuf.LinkDataPackageFragment
get() = protoForNames.also { packageAccessedHandler?.markPackageAccessed(fqName) }
@@ -46,35 +50,37 @@
}
override val classDataFinder by lazy {
- KonanClassDataFinder(proto, nameResolver)
+ KotlinNativeProtoBasedClassDataFinder(proto, nameResolver)
}
private val _memberScope by lazy {
+ val classNameList = protoForNames.classes.classNameList
/* TODO: we fake proto binary versioning for now. */
- DeserializedPackageMemberScope(
+ val memberScope = DeserializedPackageMemberScope(
this,
proto.getPackage(),
nameResolver,
KonanMetadataVersion.INSTANCE,
/* containerSource = */ null,
components
- ) { loadClassNames() }
+ ) { loadClassNames(classNameList) }
+ // Clear hard ref to proto, as class fully initialized
+ protoForNamesStore = null
+ memberScope
}
override fun getMemberScope(): DeserializedPackageMemberScope = _memberScope
private val classifierNames: Set<Name> by lazy {
val result = mutableSetOf<Name>()
- result.addAll(loadClassNames())
+ result.addAll(loadClassNames(protoForNames.classes.classNameList))
protoForNames.getPackage().typeAliasList.mapTo(result) { nameResolver.getName(it.name) }
result
}
fun hasTopLevelClassifier(name: Name): Boolean = name in classifierNames
- private fun loadClassNames(): Collection<Name> {
-
- val classNameList = protoForNames.classes.classNameList
+ private fun loadClassNames(classNameList: List<Int>): Collection<Name> {
val names = classNameList.mapNotNull {
val classId = nameResolver.getClassId(it)