From 5f1f8542939c141aa0e3d402365ac0d8f0edb4a2 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Sat, 16 Jun 2012 00:22:23 +0400 Subject: [PATCH] JavaDescriptorResolver: resolve constructors lazily This speeds up analyze a bit (profiler shown about 10% of time spent in constructor resolver during completion in KDoc). --- .../java/ClassDescriptorFromJvmBytecode.java | 71 ++++++++++++++++ .../resolve/java/JavaDescriptorResolver.java | 80 ++++++++++++------- .../descriptors/MutableClassDescriptor.java | 20 ++++- .../MutableClassDescriptorLite.java | 20 +---- 4 files changed, 139 insertions(+), 52 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/ClassDescriptorFromJvmBytecode.java diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/ClassDescriptorFromJvmBytecode.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/ClassDescriptorFromJvmBytecode.java new file mode 100644 index 00000000000..d0f122a604f --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/ClassDescriptorFromJvmBytecode.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.java; + +import com.google.common.collect.Lists; +import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassKind; +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.MutableClassDescriptorLite; +import org.jetbrains.jet.lang.resolve.lazy.LazyClassDescriptor; +import org.jetbrains.jet.lang.resolve.name.FqName; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * @author Stepan Koltsov + * + * @see LazyClassDescriptor + */ +public class ClassDescriptorFromJvmBytecode extends MutableClassDescriptorLite { + @NotNull + private final JavaDescriptorResolver javaDescriptorResolver; + @NotNull + private final JavaDescriptorResolver.ResolverBinaryClassData resolverBinaryClassData; + + + // lazy + private Collection constructors; + + public ClassDescriptorFromJvmBytecode( + @NotNull DeclarationDescriptor containingDeclaration, @NotNull ClassKind kind, + @NotNull PsiClass psiClass, @NotNull FqName fqName, + @NotNull JavaDescriptorResolver javaDescriptorResolver) { + super(containingDeclaration, kind); + this.javaDescriptorResolver = javaDescriptorResolver; + this.resolverBinaryClassData = new JavaDescriptorResolver.ResolverBinaryClassData(psiClass, fqName, this); + } + + @NotNull + public JavaDescriptorResolver.ResolverBinaryClassData getResolverBinaryClassData() { + return resolverBinaryClassData; + } + + + @NotNull + @Override + public Collection getConstructors() { + if (constructors == null) { + this.constructors = javaDescriptorResolver.resolveConstructors(resolverBinaryClassData); + } + return constructors; + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index c11bf5b052f..1a593e8a35f 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -183,9 +183,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes /** Class with instance members */ static class ResolverBinaryClassData extends ResolverScopeData { - private final MutableClassDescriptorLite classDescriptor; + private final ClassDescriptorFromJvmBytecode classDescriptor; - ResolverBinaryClassData(@NotNull PsiClass psiClass, @NotNull FqName fqName, @NotNull MutableClassDescriptorLite classDescriptor) { + ResolverBinaryClassData(@NotNull PsiClass psiClass, @NotNull FqName fqName, @NotNull ClassDescriptorFromJvmBytecode classDescriptor) { super(psiClass, null, fqName, false, classDescriptor); this.classDescriptor = classDescriptor; } @@ -360,7 +360,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes return classData; } - classData = new ResolverBinaryClassData(psiClass, fqName, new MutableClassDescriptorLite(containingDeclaration, kind)); + classData = new ClassDescriptorFromJvmBytecode( + containingDeclaration, kind, psiClass, fqName, this) + .getResolverBinaryClassData(); classDescriptorCache.put(fqName, classData); classData.classDescriptor.setName(name); classData.classDescriptor.setAnnotations(resolveAnnotations(psiClass, taskList)); @@ -392,17 +394,40 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes initializeTypeParameters(classData.typeParameters, classData.classDescriptor, "class " + psiClass.getQualifiedName()); - TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver( - classData.classDescriptor, - "class " + psiClass.getQualifiedName()); - // TODO: ugly hack: tests crash if initializeTypeParameters called with class containing proper supertypes supertypes.addAll(getSupertypes(new PsiClassWrapper(psiClass), classData, classData.getTypeParameters())); + MutableClassDescriptorLite classObject = createClassObjectDescriptor(classData.classDescriptor, psiClass); + if (classObject != null) { + classData.classDescriptor.getBuilder().setClassObjectDescriptor(classObject); + } + + trace.record(BindingContext.CLASS, psiClass, classData.classDescriptor); + + return classData; + } + + @NotNull + public Collection resolveConstructors(@NotNull ResolverBinaryClassData classData) { + Collection constructors = Lists.newArrayList(); + + PsiClass psiClass = classData.psiClass; + + TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver( + classData.classDescriptor, "class " + psiClass.getQualifiedName()); + + List typeParameters = classData.classDescriptor.getTypeConstructor().getParameters(); + PsiMethod[] psiConstructors = psiClass.getConstructors(); boolean isStatic = psiClass.hasModifierProperty(PsiModifier.STATIC); - if (psiConstructors.length == 0) { + if (classData.classDescriptor.getKind() == ClassKind.OBJECT) { + // TODO: wrong: class objects do not need visible constructors + ConstructorDescriptorImpl constructor = new ConstructorDescriptorImpl(classData.classDescriptor, new ArrayList(0), true); + constructor.initialize(new ArrayList(0), new ArrayList(0), Visibilities.PUBLIC); + constructors.add(constructor); + } + else if (psiConstructors.length == 0) { // We need to create default constructors for classes and abstract classes. // Example: // class Kotlin() : Java() {} @@ -413,8 +438,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes Collections.emptyList(), false); constructorDescriptor.initialize(typeParameters, Collections.emptyList(), classData.classDescriptor.getVisibility(), isStatic); - constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType()); - classData.classDescriptor.addConstructor(constructorDescriptor, null); + constructors.add(constructorDescriptor); trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); } if (psiClass.isAnnotationType()) { @@ -454,32 +478,32 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes } constructorDescriptor.initialize(typeParameters, valueParameters, classData.classDescriptor.getVisibility(), isStatic); - constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType()); - classData.classDescriptor.addConstructor(constructorDescriptor, null); + constructors.add(constructorDescriptor); trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor); } } else { for (PsiMethod psiConstructor : psiConstructors) { - resolveConstructor(psiClass, classData, isStatic, psiConstructor); + ConstructorDescriptor constructor = resolveConstructor(psiClass, classData, isStatic, psiConstructor); + if (constructor != null) { + constructors.add(constructor); + } } } - MutableClassDescriptorLite classObject = createClassObjectDescriptor(classData.classDescriptor, psiClass); - if (classObject != null) { - classData.classDescriptor.getBuilder().setClassObjectDescriptor(classObject); + for (ConstructorDescriptor constructor : constructors) { + ((ConstructorDescriptorImpl) constructor).setReturnType(classData.classDescriptor.getDefaultType()); } - trace.record(BindingContext.CLASS, psiClass, classData.classDescriptor); - - return classData; + return constructors; } - private void resolveConstructor(PsiClass psiClass, ResolverBinaryClassData classData, boolean aStatic, PsiMethod psiConstructor) { + @Nullable + private ConstructorDescriptor resolveConstructor(PsiClass psiClass, ResolverBinaryClassData classData, boolean aStatic, PsiMethod psiConstructor) { PsiMethodWrapper constructor = new PsiMethodWrapper(psiConstructor); if (constructor.getJetConstructor().hidden()) { - return; + return null; } ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl( @@ -496,9 +520,8 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes constructorDescriptor.initialize(classData.classDescriptor.getTypeConstructor().getParameters(), valueParameterDescriptors.descriptors, resolveVisibilityFromPsiModifiers(psiConstructor), aStatic); - constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType()); - classData.classDescriptor.addConstructor(constructorDescriptor, null); trace.record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor); + return constructorDescriptor; } static void checkPsiClassIsNotJet(PsiClass psiClass) { @@ -531,8 +554,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes checkPsiClassIsNotJet(psiClass); FqName fqName = new FqName(classObjectPsiClass.getQualifiedName()); - ResolverBinaryClassData classData = new ResolverBinaryClassData(classObjectPsiClass, fqName, - new MutableClassDescriptorLite(containing, ClassKind.OBJECT)); + ResolverBinaryClassData classData = new ClassDescriptorFromJvmBytecode( + containing, ClassKind.OBJECT, classObjectPsiClass, fqName, this) + .getResolverBinaryClassData(); classDescriptorCache.put(fqName, classData); @@ -544,12 +568,6 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes classData.classDescriptor.createTypeConstructor(); classData.classDescriptor.setScopeForMemberLookup(new JavaClassMembersScope(semanticServices, classData)); - // TODO: wrong: class objects do not need visible constructors - ConstructorDescriptorImpl constructor = new ConstructorDescriptorImpl(classData.classDescriptor, new ArrayList(0), true); - constructor.setReturnType(classData.classDescriptor.getDefaultType()); - constructor.initialize(new ArrayList(0), new ArrayList(0), Visibilities.PUBLIC); - - classData.classDescriptor.addConstructor(constructor, null); return classData.classDescriptor; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 00c6dfc712c..b78abecaf32 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -38,6 +38,7 @@ import java.util.Set; * @author abreslav */ public class MutableClassDescriptor extends MutableClassDescriptorLite implements ClassDescriptorFromSource { + private final Set constructors = Sets.newLinkedHashSet(); private ConstructorDescriptor primaryConstructor; private final Set declaredCallableMembers = Sets.newHashSet(); @@ -72,9 +73,15 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Override public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor, @NotNull BindingTrace trace) { - super.addConstructor(constructorDescriptor, trace); + if (constructorDescriptor.getContainingDeclaration() != this) { + throw new IllegalStateException("invalid containing declaration of constructor"); + } + constructors.add(constructorDescriptor); + if (defaultType != null) { + ((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType()); + } + if (constructorDescriptor.isPrimary()) { setUpScopeForInitializers(constructorDescriptor); for (ValueParameterDescriptor valueParameterDescriptor : constructorDescriptor.getValueParameters()) { @@ -93,6 +100,12 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement addConstructor(constructorDescriptor, trace); } + @NotNull + @Override + public Set getConstructors() { + return constructors; + } + @Override @Nullable public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() { @@ -141,6 +154,9 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement @Override public void createTypeConstructor() { super.createTypeConstructor(); + for (FunctionDescriptor functionDescriptor : getConstructors()) { + ((ConstructorDescriptorImpl) functionDescriptor).setReturnType(getDefaultType()); + } scopeForMemberResolution.setImplicitReceiver(new ClassReceiver(this)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java index 8531b28df04..11c883ee685 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptorLite.java @@ -36,9 +36,8 @@ import java.util.*; /** * @author Stepan Koltsov */ -public class MutableClassDescriptorLite extends ClassDescriptorBase +public abstract class MutableClassDescriptorLite extends ClassDescriptorBase implements WithDeferredResolve { - private final Set constructors = Sets.newLinkedHashSet(); private List annotations = Lists.newArrayList(); @@ -134,9 +133,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase getName().getName(), typeParameters, supertypes); - for (FunctionDescriptor functionDescriptor : constructors) { - ((ConstructorDescriptorImpl) functionDescriptor).setReturnType(getDefaultType()); - } } private WritableScope getScopeForMemberLookupAsWritableScope() { @@ -145,12 +141,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase } - @NotNull - @Override - public Collection getConstructors() { - return constructors; - } - @NotNull public JetScope getScopeForMemberLookup() { return scopeForMemberLookup; @@ -205,14 +195,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase } - public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor, @Nullable BindingTrace trace) { - assert constructorDescriptor.getContainingDeclaration() == this; - constructors.add(constructorDescriptor); - if (defaultType != null) { - ((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType()); - } - } - @Override @Nullable public MutableClassDescriptorLite getClassObjectDescriptor() {