Optimize memory-footprint for ClassifierResolutionContext
Use immutable maps for inner classes/type parameters in nested contexts instead of making copies for each of them
This commit is contained in:
+22
-23
@@ -17,53 +17,52 @@
|
|||||||
package org.jetbrains.kotlin.load.java.structure.impl.classFiles
|
package org.jetbrains.kotlin.load.java.structure.impl.classFiles
|
||||||
|
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import gnu.trove.THashMap
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap
|
||||||
|
import org.jetbrains.kotlin.util.javaslang.ImmutableMap
|
||||||
|
import org.jetbrains.kotlin.util.javaslang.getOrNull
|
||||||
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
typealias ClassIdToJavaClass = (ClassId) -> JavaClass?
|
typealias ClassIdToJavaClass = (ClassId) -> JavaClass?
|
||||||
|
|
||||||
class ClassifierResolutionContext private constructor(
|
class ClassifierResolutionContext private constructor(
|
||||||
private val classesByQName: ClassIdToJavaClass,
|
private val classesByQName: ClassIdToJavaClass,
|
||||||
// Note that this data is fully mutable and its correctness is based on the assumption
|
// Note that this data is fully mutable and its correctness is based on the assumption
|
||||||
// that nobody starts resolving classifier until type parameters and inner classes are initialized.
|
// that nobody starts resolving classifier until type parameters and inner classes are initialized.
|
||||||
// Currently it's implemented through laziness in the PlainJavaClassifierType.
|
// Currently it's implemented through laziness in the PlainJavaClassifierType.
|
||||||
private var typeParameters: MutableMap<String, JavaTypeParameter>?,
|
private var typeParameters: ImmutableMap<String, JavaTypeParameter>,
|
||||||
private var innerClasses: MutableMap<String, InnerClassInfo>?
|
private var innerClasses: ImmutableMap<String, InnerClassInfo>
|
||||||
) {
|
) {
|
||||||
constructor(classesByQName: ClassIdToJavaClass) : this(classesByQName, null, null)
|
constructor(classesByQName: ClassIdToJavaClass) : this(classesByQName, ImmutableHashMap.empty(), ImmutableHashMap.empty())
|
||||||
|
|
||||||
internal data class Result(val classifier: JavaClassifier?, val qualifiedName: String)
|
internal data class Result(val classifier: JavaClassifier?, val qualifiedName: String)
|
||||||
|
|
||||||
private class InnerClassInfo(val outerInternalName: String, val simpleName: String)
|
private class InnerClassInfo(val outerInternalName: String, val simpleName: String)
|
||||||
|
|
||||||
internal fun addInnerClass(innerInternalName: String, outerInternalName: String, simpleName: String) {
|
internal fun addInnerClass(innerInternalName: String, outerInternalName: String, simpleName: String) {
|
||||||
if (innerClasses == null) {
|
innerClasses = innerClasses.put(innerInternalName, InnerClassInfo(outerInternalName, simpleName))
|
||||||
innerClasses = THashMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
innerClasses!!.put(innerInternalName, InnerClassInfo(outerInternalName, simpleName))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun addTypeParameters(newTypeParameters: Collection<JavaTypeParameter>) {
|
internal fun addTypeParameters(newTypeParameters: Collection<JavaTypeParameter>) {
|
||||||
if (newTypeParameters.isEmpty()) return
|
if (newTypeParameters.isEmpty()) return
|
||||||
if (typeParameters == null) {
|
|
||||||
typeParameters = THashMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
newTypeParameters.associateByTo(typeParameters!!) { it.name.identifier }
|
typeParameters =
|
||||||
|
newTypeParameters
|
||||||
|
.fold(typeParameters) { acc, typeParameter ->
|
||||||
|
acc.put(typeParameter.name.identifier, typeParameter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun resolveClass(classId: ClassId) = Result(classesByQName(classId), classId.asSingleFqName().asString())
|
private fun resolveClass(classId: ClassId) = Result(classesByQName(classId), classId.asSingleFqName().asString())
|
||||||
internal fun resolveTypeParameter(name: String) = Result(typeParameters?.get(name), name)
|
internal fun resolveTypeParameter(name: String) = Result(typeParameters.getOrNull(name), name)
|
||||||
|
|
||||||
internal fun copyForMember() =
|
internal fun copyForMember() = ClassifierResolutionContext(classesByQName, typeParameters, innerClasses)
|
||||||
ClassifierResolutionContext(classesByQName, typeParameters?.let(::THashMap), innerClasses?.let(::THashMap))
|
|
||||||
|
|
||||||
// See com.intellij.psi.impl.compiled.StubBuildingVisitor.createMapping(byte[])
|
// See com.intellij.psi.impl.compiled.StubBuildingVisitor.createMapping(byte[])
|
||||||
internal fun mapInternalNameToClassId(internalName: String): ClassId {
|
internal fun mapInternalNameToClassId(internalName: String): ClassId {
|
||||||
@@ -79,7 +78,7 @@ class ClassifierResolutionContext private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ('$' in internalName) {
|
if ('$' in internalName) {
|
||||||
val innerClassInfo = innerClasses?.get(internalName) ?: return mapInternalNameToClassIdNaively(internalName)
|
val innerClassInfo = innerClasses.getOrNull(internalName) ?: return mapInternalNameToClassIdNaively(internalName)
|
||||||
if (Name.isValidIdentifier(innerClassInfo.simpleName)) {
|
if (Name.isValidIdentifier(innerClassInfo.simpleName)) {
|
||||||
val outerClassId = mapInternalNameToClassId(innerClassInfo.outerInternalName)
|
val outerClassId = mapInternalNameToClassId(innerClassInfo.outerInternalName)
|
||||||
return outerClassId.createNestedClassId(Name.identifier(innerClassInfo.simpleName))
|
return outerClassId.createNestedClassId(Name.identifier(innerClassInfo.simpleName))
|
||||||
@@ -107,7 +106,7 @@ class ClassifierResolutionContext private constructor(
|
|||||||
val outerFqName = FqName(substrings[0].replace('/', '.'))
|
val outerFqName = FqName(substrings[0].replace('/', '.'))
|
||||||
val packageFqName = outerFqName.parent()
|
val packageFqName = outerFqName.parent()
|
||||||
val relativeName =
|
val relativeName =
|
||||||
FqName(outerFqName.shortName().asString() + "." + substrings.subList(1, substrings.size).joinToString("."))
|
FqName(outerFqName.shortName().asString() + "." + substrings.subList(1, substrings.size).joinToString("."))
|
||||||
|
|
||||||
return ClassId(packageFqName, relativeName, false)
|
return ClassId(packageFqName, relativeName, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,3 +29,4 @@ operator fun <T> Tuple2<T, *>.component1(): T = _1()
|
|||||||
operator fun <T> Tuple2<*, T>.component2(): T = _2()
|
operator fun <T> Tuple2<*, T>.component2(): T = _2()
|
||||||
|
|
||||||
fun <T> Option<T>.getOrNull(): T? = getOrElse(null as T?)
|
fun <T> Option<T>.getOrNull(): T? = getOrElse(null as T?)
|
||||||
|
fun <K, V> ImmutableMap<K, V>.getOrNull(k: K): V? = get(k)?.getOrElse(null as V?)
|
||||||
|
|||||||
Reference in New Issue
Block a user