From 782f221ab59ff7abae2c746d0f9bb0127cc4cb8b Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 7 Aug 2018 13:02:57 +0700 Subject: [PATCH] Optimize memory-footprint for ClassifierResolutionContext Use immutable maps for inner classes/type parameters in nested contexts instead of making copies for each of them --- .../classFiles/ClassifierResolutionContext.kt | 45 +++++++++---------- .../util/javaslang/javaslangAdapters.kt | 1 + 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt index 9a56272f985..97948dabe2b 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt @@ -17,53 +17,52 @@ package org.jetbrains.kotlin.load.java.structure.impl.classFiles 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.JavaClassifier import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName 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 typealias ClassIdToJavaClass = (ClassId) -> JavaClass? class ClassifierResolutionContext private constructor( - private val classesByQName: ClassIdToJavaClass, - // 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. - // Currently it's implemented through laziness in the PlainJavaClassifierType. - private var typeParameters: MutableMap?, - private var innerClasses: MutableMap? + private val classesByQName: ClassIdToJavaClass, + // 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. + // Currently it's implemented through laziness in the PlainJavaClassifierType. + private var typeParameters: ImmutableMap, + private var innerClasses: ImmutableMap ) { - 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) private class InnerClassInfo(val outerInternalName: String, val simpleName: String) internal fun addInnerClass(innerInternalName: String, outerInternalName: String, simpleName: String) { - if (innerClasses == null) { - innerClasses = THashMap() - } - - innerClasses!!.put(innerInternalName, InnerClassInfo(outerInternalName, simpleName)) + innerClasses = innerClasses.put(innerInternalName, InnerClassInfo(outerInternalName, simpleName)) } internal fun addTypeParameters(newTypeParameters: Collection) { 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()) - internal fun resolveTypeParameter(name: String) = Result(typeParameters?.get(name), name) + private fun resolveClass(classId: ClassId) = Result(classesByQName(classId), classId.asSingleFqName().asString()) + internal fun resolveTypeParameter(name: String) = Result(typeParameters.getOrNull(name), name) - internal fun copyForMember() = - ClassifierResolutionContext(classesByQName, typeParameters?.let(::THashMap), innerClasses?.let(::THashMap)) + internal fun copyForMember() = ClassifierResolutionContext(classesByQName, typeParameters, innerClasses) // See com.intellij.psi.impl.compiled.StubBuildingVisitor.createMapping(byte[]) internal fun mapInternalNameToClassId(internalName: String): ClassId { @@ -79,7 +78,7 @@ class ClassifierResolutionContext private constructor( } if ('$' in internalName) { - val innerClassInfo = innerClasses?.get(internalName) ?: return mapInternalNameToClassIdNaively(internalName) + val innerClassInfo = innerClasses.getOrNull(internalName) ?: return mapInternalNameToClassIdNaively(internalName) if (Name.isValidIdentifier(innerClassInfo.simpleName)) { val outerClassId = mapInternalNameToClassId(innerClassInfo.outerInternalName) return outerClassId.createNestedClassId(Name.identifier(innerClassInfo.simpleName)) @@ -107,7 +106,7 @@ class ClassifierResolutionContext private constructor( val outerFqName = FqName(substrings[0].replace('/', '.')) val packageFqName = outerFqName.parent() 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) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/util/javaslang/javaslangAdapters.kt b/compiler/frontend/src/org/jetbrains/kotlin/util/javaslang/javaslangAdapters.kt index 340d0a4b15f..e1d8bc16962 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/util/javaslang/javaslangAdapters.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/util/javaslang/javaslangAdapters.kt @@ -29,3 +29,4 @@ operator fun Tuple2.component1(): T = _1() operator fun Tuple2<*, T>.component2(): T = _2() fun Option.getOrNull(): T? = getOrElse(null as T?) +fun ImmutableMap.getOrNull(k: K): V? = get(k)?.getOrElse(null as V?)