From 1eea128b291f212f7efdb4d5532b9240d37fc50e Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Fri, 2 Nov 2012 21:08:52 +0400 Subject: [PATCH] Restructure JavaClassResolver caches to contain ClassDescriptor instead of ResolverClassData --- .../java/data/ResolverBinaryClassData.java | 6 -- .../java/resolver/JavaClassResolver.java | 63 +++++++++++++------ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/data/ResolverBinaryClassData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/data/ResolverBinaryClassData.java index 280af165fc4..7ec3d35d727 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/data/ResolverBinaryClassData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/data/ResolverBinaryClassData.java @@ -34,10 +34,4 @@ public class ResolverBinaryClassData extends ResolverClassData { ) { super(psiClass, null, fqName, false, classDescriptor); } - - public ResolverBinaryClassData(boolean negative) { - super(negative); - } - - public static final ResolverClassData NEGATIVE = new ResolverBinaryClassData(true); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java index 39aa55ff6ca..a6883844229 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiModifier; @@ -29,7 +30,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.*; -import org.jetbrains.jet.lang.resolve.java.data.ResolverBinaryClassData; import org.jetbrains.jet.lang.resolve.java.data.ResolverClassData; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation; @@ -45,12 +45,14 @@ import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; public final class JavaClassResolver { // NOTE: this complexity is introduced because class descriptors do not always have valid fqnames (class objects) - private final Map classDescriptorCache = - new THashMap(new TObjectHashingStrategy() { + @NotNull + private final Map classDescriptorCache = + new THashMap(new TObjectHashingStrategy() { @Override public int computeHashCode(FqNameBase o) { if (o instanceof FqName) { @@ -66,6 +68,9 @@ public final class JavaClassResolver { } }); + @NotNull + private final Set unresolvedCache = Sets.newHashSet(); + private BindingTrace trace; private JavaDescriptorResolver javaDescriptorResolver; private JavaSignatureResolver signatureResolver; @@ -154,9 +159,14 @@ public final class JavaClassResolver { } // Not let's take a descriptor of a Java class - ResolverClassData classData = classDescriptorCache.get(javaClassToKotlinFqName(qualifiedName)); - if (classData != null) { - return classData.getClassDescriptor(); + FqNameUnsafe fqName = javaClassToKotlinFqName(qualifiedName); + ClassDescriptor cachedDescriptor = classDescriptorCache.get(fqName); + if (cachedDescriptor != null) { + return cachedDescriptor; + } + + if (unresolvedCache.contains(fqName)) { + return null; } return doResolveClass(qualifiedName, tasks); @@ -166,18 +176,17 @@ public final class JavaClassResolver { private ClassDescriptor doResolveClass(@NotNull FqName qualifiedName, @NotNull PostponedTasks tasks) { PsiClass psiClass = psiClassFinder.findPsiClass(qualifiedName, PsiClassFinder.RuntimeClassesHandleMode.THROW); if (psiClass == null) { - cacheNegativeValue(qualifiedName); + cacheNegativeValue(javaClassToKotlinFqName(qualifiedName)); return null; } - ResolverClassData classData = createJavaClassDescriptor(qualifiedName, psiClass, tasks); - return classData.getClassDescriptor(); + return createJavaClassDescriptor(qualifiedName, psiClass, tasks); } - private void cacheNegativeValue(@NotNull FqName qualifiedName) { - ResolverClassData oldValue = classDescriptorCache.put(javaClassToKotlinFqName(qualifiedName), ResolverBinaryClassData.NEGATIVE); - if (oldValue != null) { + private void cacheNegativeValue(@NotNull FqNameBase qualifiedName) { + if (unresolvedCache.contains(qualifiedName) || classDescriptorCache.containsKey(qualifiedName)) { throw new IllegalStateException("rewrite at " + qualifiedName); } + unresolvedCache.add(qualifiedName); } private static boolean isTraitImplementation(@NotNull FqName qualifiedName) { @@ -186,7 +195,7 @@ public final class JavaClassResolver { } @NotNull - private ResolverClassData createJavaClassDescriptor( + private ClassDescriptor createJavaClassDescriptor( @NotNull FqName fqName, @NotNull final PsiClass psiClass, @NotNull PostponedTasks taskList ) { @@ -196,12 +205,14 @@ public final class JavaClassResolver { ClassOrNamespaceDescriptor containingDeclaration = resolveParentDescriptor(psiClass); // class may be resolved during resolution of parent - ResolverClassData classData = classDescriptorCache.get(javaClassToKotlinFqName(fqName)); - if (classData != null) { - return classData; + ClassDescriptor cachedDescriptor = classDescriptorCache.get(fqName); + if (cachedDescriptor != null) { + return cachedDescriptor; } - return doCreateClassDescriptor(fqName, psiClass, taskList, containingDeclaration); + assert (!unresolvedCache.contains(fqName)) : "We can resolve the class, so it can't be 'unresolved' during parent resolution"; + + return doCreateClassDescriptor(fqName, psiClass, taskList, containingDeclaration).getClassDescriptor(); } @NotNull @@ -217,7 +228,7 @@ public final class JavaClassResolver { = new ClassDescriptorFromJvmBytecode(containingDeclaration, kind, psiClass, fqName, javaDescriptorResolver); ResolverClassData classData = classDescriptor.getResolverBinaryClassData(); - classDescriptorCache.put(javaClassToKotlinFqName(fqName), classData); + cache(javaClassToKotlinFqName(fqName), classDescriptor); classDescriptor.setName(Name.identifier(psiClass.getName())); List typeParameterDescriptorInitializations @@ -239,7 +250,8 @@ public final class JavaClassResolver { supertypes.addAll(supertypesResolver.getSupertypes(new PsiClassWrapper(psiClass), classData, classTypeParameters)); ResolverClassData classObjectData = classObjectResolver.createClassObjectDescriptor(classDescriptor, psiClass); - classDescriptorCache.put(DescriptorResolverUtils.getFqNameForClassObject(psiClass), classObjectData); + cache(DescriptorResolverUtils.getFqNameForClassObject(psiClass), + classObjectData != null ? classObjectData.getClassDescriptor() : null); if (classObjectData != null) { ClassDescriptorFromJvmBytecode classObjectDescriptor = classObjectData.getClassDescriptor(); classDescriptor.getBuilder().setClassObjectDescriptor(classObjectDescriptor); @@ -252,6 +264,16 @@ public final class JavaClassResolver { return classData; } + private void cache(@NotNull FqNameBase fqName, @Nullable ClassDescriptor classDescriptor) { + if (classDescriptor == null) { + cacheNegativeValue(fqName); + } + else { + ClassDescriptor oldValue = classDescriptorCache.put(fqName, classDescriptor); + assert oldValue == null; + } + } + @NotNull private static List getTypeParametersDescriptors( @NotNull List typeParameterDescriptorInitializations @@ -279,7 +301,8 @@ public final class JavaClassResolver { FqName fqName = new FqName(qualifiedName); assert fqName.equals(desiredFqName); - if (classDescriptorCache.containsKey(javaClassToKotlinFqName(fqName))) { + FqNameUnsafe correctedName = javaClassToKotlinFqName(fqName); + if (classDescriptorCache.containsKey(correctedName) || unresolvedCache.contains(correctedName)) { throw new IllegalStateException(qualifiedName); } }