Reduce memory footprint after functions substitution

Do not recreate new instances if descriptors' parts remain
effectively the same
This commit is contained in:
Denis Zharkov
2017-05-24 16:13:54 +03:00
parent 4a73fbb70a
commit e2ce285ec3
6 changed files with 102 additions and 7 deletions
@@ -20,14 +20,18 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.findFirstFunction
import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
import org.jetbrains.kotlin.types.lowerIfFlexible
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.upperIfFlexible
import org.junit.Test
@@ -54,4 +58,49 @@ class MemoryOptimizationsTest : KtUsefulTestCase() {
// NullableSimpleType should store and return the same instance as lower bound of flexible type
assertTrue(parameterType.lowerIfFlexible() === upperBound.makeNullableAsSpecified(false))
}
@Test
fun testSubstitutorDoNotRecreateUnchangedDescriptor() {
val text =
"""
|package test
|interface A<T> : java.lang.Appendable {
| fun foo(x: T)
|}
""".trimMargin()
val environment =
KotlinTestUtils
.createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(
myTestRootDisposable, ConfigurationKind.ALL, TestJdkKind.FULL_JDK
)
val moduleDescriptor =
JvmResolveUtil.analyze(
KotlinTestUtils.createFile("main.kt", text, environment.project),
environment
).moduleDescriptor
val aClass =
moduleDescriptor.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("test.A")))!!
val memberScope =
aClass.getMemberScope(
TypeConstructorSubstitution.create(
aClass.typeConstructor, listOf(moduleDescriptor.builtIns.stringType.asTypeProjection())
)
)
val append =
memberScope.findFirstFunction("append") {
it.valueParameters.singleOrNull()?.type?.let(KotlinBuiltIns::isChar) == false
}
assertTrue(append.original === append)
val foo = memberScope.findSingleFunction(Name.identifier("foo"))
assertTrue(foo.original !== foo)
}
}
@@ -56,6 +56,7 @@ public abstract class AbstractReceiverParameterDescriptor extends DeclarationDes
}
if (substitutedType == null) return null;
if (substitutedType == getType()) return this;
return new ReceiverParameterDescriptorImpl(getContainingDeclaration(), new TransientReceiver(substitutedType));
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.descriptors.impl;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.functions.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -334,7 +335,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
if (originalSubstitutor.isEmpty()) {
return this;
}
return newCopyBuilder(originalSubstitutor).setOriginal(getOriginal()).build();
return newCopyBuilder(originalSubstitutor).setOriginal(getOriginal()).setJustForTypeSubstitution(true).build();
}
@Nullable
@@ -370,6 +371,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
private boolean isHiddenForResolutionEverywhereBesideSupercalls = isHiddenForResolutionEverywhereBesideSupercalls();
private Map<UserDataKey<?>, Object> userDataMap = new LinkedHashMap<UserDataKey<?>, Object>();
private Boolean newHasSynthesizedParameterNames = null;
protected boolean justForTypeSubstitution = false;
public CopyConfiguration(
@NotNull TypeSubstitution substitution,
@@ -553,6 +555,12 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
public TypeSubstitution getSubstitution() {
return substitution;
}
@NotNull
public CopyConfiguration setJustForTypeSubstitution(boolean value) {
justForTypeSubstitution = value;
return this;
}
}
@Override
@@ -571,6 +579,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
@Nullable
protected FunctionDescriptor doSubstitute(@NotNull CopyConfiguration configuration) {
boolean[] wereChanges = new boolean[1];
Annotations resultAnnotations =
configuration.additionalAnnotations != null
? AnnotationsKt.composeAnnotations(getAnnotations(), configuration.additionalAnnotations)
@@ -583,10 +592,12 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
List<TypeParameterDescriptor> unsubstitutedTypeParameters =
configuration.newTypeParameters == null ? getTypeParameters() : configuration.newTypeParameters;
wereChanges[0] |= !unsubstitutedTypeParameters.isEmpty();
List<TypeParameterDescriptor> substitutedTypeParameters =
new ArrayList<TypeParameterDescriptor>(unsubstitutedTypeParameters.size());
final TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(
unsubstitutedTypeParameters, configuration.substitution, substitutedDescriptor, substitutedTypeParameters
unsubstitutedTypeParameters, configuration.substitution, substitutedDescriptor, substitutedTypeParameters, wereChanges
);
KotlinType substitutedReceiverParameterType = null;
@@ -595,6 +606,8 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
if (substitutedReceiverParameterType == null) {
return null;
}
wereChanges[0] |= substitutedReceiverParameterType != configuration.newExtensionReceiverParameterType;
}
ReceiverParameterDescriptor substitutedExpectedThis = null;
@@ -613,11 +626,13 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
if (substitutedExpectedThis == null) {
return null;
}
wereChanges[0] |= substitutedExpectedThis != configuration.dispatchReceiverParameter;
}
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(
substitutedDescriptor, configuration.newValueParameterDescriptors, substitutor, configuration.dropOriginalInContainingParts,
configuration.preserveSourceElement
configuration.preserveSourceElement, wereChanges
);
if (substitutedValueParameters == null) {
return null;
@@ -628,6 +643,12 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
return null;
}
wereChanges[0] |= substitutedReturnType != configuration.newReturnType;
if (!wereChanges[0] && configuration.justForTypeSubstitution) {
return this;
}
substitutedDescriptor.initialize(
substitutedReceiverParameterType,
substitutedExpectedThis,
@@ -682,7 +703,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
if (configuration.copyOverrides && !getOriginal().getOverriddenDescriptors().isEmpty()) {
if (configuration.substitution.isEmpty()) {
Function0<Set<FunctionDescriptor>> overriddenFunctionsTask = lazyOverriddenFunctionsTask;
Function0<Collection<FunctionDescriptor>> overriddenFunctionsTask = lazyOverriddenFunctionsTask;
if (overriddenFunctionsTask != null) {
substitutedDescriptor.lazyOverriddenFunctionsTask = overriddenFunctionsTask;
}
@@ -753,7 +774,8 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
@NotNull TypeSubstitutor substitutor,
boolean dropOriginal,
boolean preserveSourceElement
boolean preserveSourceElement,
@Nullable boolean[] wereChanges
) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(unsubstitutedValueParameters.size());
for (ValueParameterDescriptor unsubstitutedValueParameter : unsubstitutedValueParameters) {
@@ -763,6 +785,11 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
KotlinType substituteVarargElementType =
varargElementType == null ? null : substitutor.substitute(varargElementType, Variance.IN_VARIANCE);
if (substitutedType == null) return null;
if (substitutedType != unsubstitutedValueParameter.getType() || varargElementType != substituteVarargElementType) {
if (wereChanges != null) {
wereChanges[0] = true;
}
}
result.add(
new ValueParameterDescriptorImpl(
substitutedDescriptor,
@@ -385,7 +385,7 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
if (newSetter != null) {
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(
newSetter, setter.getValueParameters(), substitutor, /* dropOriginal = */ false,
false
false, null
);
if (substitutedValueParameters == null) {
// The setter is projected out, e.g. in this case:
@@ -179,7 +179,8 @@ class TypeAliasConstructorDescriptorImpl private constructor(
val valueParameters =
FunctionDescriptorImpl.getSubstitutedValueParameters(
typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass, false, false
typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass, false, false,
null
) ?: return null
val returnType = run {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.types;
import org.jetbrains.annotations.Mutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.SourceElement;
@@ -38,6 +39,17 @@ public class DescriptorSubstitutor {
@NotNull TypeSubstitution originalSubstitution,
@NotNull DeclarationDescriptor newContainingDeclaration,
@NotNull @Mutable List<TypeParameterDescriptor> result
) {
return substituteTypeParameters(typeParameters, originalSubstitution, newContainingDeclaration, result, null);
}
@NotNull
public static TypeSubstitutor substituteTypeParameters(
@ReadOnly @NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull TypeSubstitution originalSubstitution,
@NotNull DeclarationDescriptor newContainingDeclaration,
@NotNull @Mutable List<TypeParameterDescriptor> result,
@Nullable boolean[] wereChanges
) {
Map<TypeConstructor, TypeProjection> mutableSubstitution = new HashMap<TypeConstructor, TypeProjection>();
@@ -69,6 +81,11 @@ public class DescriptorSubstitutor {
for (KotlinType upperBound : descriptor.getUpperBounds()) {
KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.IN_VARIANCE);
assert substitutedBound != null : "Upper bound failed to substitute: " + descriptor;
if (substitutedBound != upperBound && wereChanges != null) {
wereChanges[0] = true;
}
substituted.addUpperBound(substitutedBound);
}
substituted.setInitialized();