Lazy member scopes are now thread-safe.

NOTE: in this implementation there will be exceptions from rewrites on the trace.
This commit is contained in:
Andrey Breslav
2013-02-06 18:35:59 +04:00
parent 1cac7c1a41
commit 59b78e3628
5 changed files with 70 additions and 27 deletions
@@ -16,8 +16,6 @@
package org.jetbrains.jet.lang.resolve.lazy; package org.jetbrains.jet.lang.resolve.lazy;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -29,6 +27,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentMap;
import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve; import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
@@ -37,15 +36,14 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
protected final DP declarationProvider; protected final DP declarationProvider;
protected final D thisDescriptor; protected final D thisDescriptor;
protected boolean allDescriptorsComputed = false; private final ConcurrentMap<Name, ClassDescriptor> classDescriptors;
private final ConcurrentMap<Name, ClassDescriptor> objectDescriptors;
private final Map<Name, ClassDescriptor> classDescriptors = Maps.newHashMap(); private final ConcurrentMap<Name, Set<FunctionDescriptor>> functionDescriptors;
private final Map<Name, ClassDescriptor> objectDescriptors = Maps.newHashMap(); private final ConcurrentMap<Name, Set<VariableDescriptor>> propertyDescriptors;
protected final Map<Name, Set<FunctionDescriptor>> functionDescriptors = Maps.newHashMap(); private final Collection<DeclarationDescriptor> allDescriptors;
private final Map<Name, Set<VariableDescriptor>> propertyDescriptors = Maps.newHashMap(); protected volatile boolean allDescriptorsComputed = false;
protected final List<DeclarationDescriptor> allDescriptors = Lists.newArrayList();
protected AbstractLazyMemberScope( protected AbstractLazyMemberScope(
@NotNull ResolveSession resolveSession, @NotNull ResolveSession resolveSession,
@@ -55,10 +53,17 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
this.resolveSession = resolveSession; this.resolveSession = resolveSession;
this.declarationProvider = declarationProvider; this.declarationProvider = declarationProvider;
this.thisDescriptor = thisDescriptor; this.thisDescriptor = thisDescriptor;
StorageManager storageManager = resolveSession.getStorageManager();
this.classDescriptors = storageManager.createConcurrentMap();
this.objectDescriptors = storageManager.createConcurrentMap();
this.functionDescriptors = storageManager.createConcurrentMap();
this.propertyDescriptors = storageManager.createConcurrentMap();
this.allDescriptors = storageManager.createConcurrentCollection();
} }
@Nullable @Nullable
private ClassDescriptor getClassOrObjectDescriptor(@NotNull Map<Name, ClassDescriptor> cache, @NotNull Name name, boolean object) { private ClassDescriptor getClassOrObjectDescriptor(@NotNull ConcurrentMap<Name, ClassDescriptor> cache, @NotNull Name name, boolean object) {
ClassDescriptor known = cache.get(name); ClassDescriptor known = cache.get(name);
if (known != null) return known; if (known != null) return known;
@@ -77,9 +82,11 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
ClassDescriptor classDescriptor = new LazyClassDescriptor(resolveSession, thisDescriptor, name, ClassDescriptor classDescriptor = new LazyClassDescriptor(resolveSession, thisDescriptor, name,
JetClassInfoUtil.createClassLikeInfo(classOrObjectDeclaration)); JetClassInfoUtil.createClassLikeInfo(classOrObjectDeclaration));
cache.put(name, classDescriptor); ClassDescriptor oldValue = cache.putIfAbsent(name, classDescriptor);
if (oldValue != null) return oldValue;
if (!object) { if (!object) {
allDescriptors.add(classDescriptor); registerDescriptor(classDescriptor);
} }
result = classDescriptor; result = classDescriptor;
@@ -123,8 +130,10 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
getNonDeclaredFunctions(name, result); getNonDeclaredFunctions(name, result);
if (!result.isEmpty()) { if (!result.isEmpty()) {
functionDescriptors.put(name, result); Set<FunctionDescriptor> oldValue = functionDescriptors.putIfAbsent(name, result);
allDescriptors.addAll(result); if (oldValue != null) return oldValue;
registerDescriptors(result);
} }
return result; return result;
} }
@@ -170,8 +179,10 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
getNonDeclaredProperties(name, result); getNonDeclaredProperties(name, result);
if (!result.isEmpty()) { if (!result.isEmpty()) {
propertyDescriptors.put(name, result); Set<VariableDescriptor> oldValue = propertyDescriptors.putIfAbsent(name, result);
allDescriptors.addAll(result); if (oldValue != null) return oldValue;
registerDescriptors(result);
} }
return result; return result;
} }
@@ -208,6 +219,16 @@ public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, D
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
protected void registerDescriptor(@NotNull DeclarationDescriptor descriptor) {
assert !allDescriptorsComputed : "getAllDescriptors() has been called already";
allDescriptors.add(descriptor);
}
protected void registerDescriptors(@NotNull Collection<? extends DeclarationDescriptor> descriptors) {
assert !allDescriptorsComputed : "getAllDescriptors() has been called already";
allDescriptors.addAll(descriptors);
}
@NotNull @NotNull
@Override @Override
public Collection<DeclarationDescriptor> getAllDescriptors() { public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -16,7 +16,9 @@
package org.jetbrains.jet.lang.resolve.lazy; package org.jetbrains.jet.lang.resolve.lazy;
import com.google.common.base.Optional;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -64,8 +66,7 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
Collection<T> extract(@NotNull JetType extractFrom, @NotNull Name name); Collection<T> extract(@NotNull JetType extractFrom, @NotNull Name name);
} }
private ConstructorDescriptor primaryConstructor; private final LazyValue<Optional<ConstructorDescriptor>> primaryConstructor;
private boolean primaryConstructorResolved = false;
public LazyClassMemberScope( public LazyClassMemberScope(
@NotNull ResolveSession resolveSession, @NotNull ResolveSession resolveSession,
@@ -73,6 +74,12 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
@NotNull LazyClassDescriptor thisClass @NotNull LazyClassDescriptor thisClass
) { ) {
super(resolveSession, declarationProvider, thisClass); super(resolveSession, declarationProvider, thisClass);
this.primaryConstructor = resolveSession.getStorageManager().createLazyValue(new Computable<Optional<ConstructorDescriptor>>() {
@Override
public Optional<ConstructorDescriptor> compute() {
return Optional.fromNullable(resolvePrimaryConstructor());
}
});
} }
@NotNull @NotNull
@@ -331,9 +338,12 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
@Nullable @Nullable
public ConstructorDescriptor getPrimaryConstructor() { public ConstructorDescriptor getPrimaryConstructor() {
if (primaryConstructorResolved) { return primaryConstructor.get().orNull();
return primaryConstructor; }
}
@Nullable
private ConstructorDescriptor resolvePrimaryConstructor() {
ConstructorDescriptor primaryConstructor = null;
if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) { if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) {
JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject(); JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
if (!thisDescriptor.getKind().isObject()) { if (!thisDescriptor.getKind().isObject()) {
@@ -353,7 +363,6 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
primaryConstructor = constructor; primaryConstructor = constructor;
} }
} }
primaryConstructorResolved = true;
return primaryConstructor; return primaryConstructor;
} }
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.resolve.lazy; package org.jetbrains.jet.lang.resolve.lazy;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetDeclaration;
@@ -26,23 +25,26 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentMap;
public class LazyPackageMemberScope extends AbstractLazyMemberScope<NamespaceDescriptor, PackageMemberDeclarationProvider> { public class LazyPackageMemberScope extends AbstractLazyMemberScope<NamespaceDescriptor, PackageMemberDeclarationProvider> {
private final Map<Name, NamespaceDescriptor> packageDescriptors = Maps.newHashMap(); private final ConcurrentMap<Name, NamespaceDescriptor> packageDescriptors;
public LazyPackageMemberScope(@NotNull ResolveSession resolveSession, public LazyPackageMemberScope(@NotNull ResolveSession resolveSession,
@NotNull PackageMemberDeclarationProvider declarationProvider, @NotNull PackageMemberDeclarationProvider declarationProvider,
@NotNull NamespaceDescriptor thisPackage) { @NotNull NamespaceDescriptor thisPackage) {
super(resolveSession, declarationProvider, thisPackage); super(resolveSession, declarationProvider, thisPackage);
this.packageDescriptors = resolveSession.getStorageManager().createConcurrentMap();
} }
@Override @Override
public NamespaceDescriptor getNamespace(@NotNull Name name) { public NamespaceDescriptor getNamespace(@NotNull Name name) {
NamespaceDescriptor known = packageDescriptors.get(name); NamespaceDescriptor known = packageDescriptors.get(name);
if (known != null) return known; if (known != null) return known;
if (allDescriptorsComputed) return null; if (allDescriptorsComputed) return null;
if (!declarationProvider.isPackageDeclared(name)) return null; if (!declarationProvider.isPackageDeclared(name)) return null;
@@ -52,8 +54,10 @@ public class LazyPackageMemberScope extends AbstractLazyMemberScope<NamespaceDes
assert packageMemberDeclarationProvider != null : "Package is declared, but declaration provider is not found: " + name; assert packageMemberDeclarationProvider != null : "Package is declared, but declaration provider is not found: " + name;
NamespaceDescriptor namespaceDescriptor = new LazyPackageDescriptor(thisDescriptor, name, resolveSession, packageMemberDeclarationProvider); NamespaceDescriptor namespaceDescriptor = new LazyPackageDescriptor(thisDescriptor, name, resolveSession, packageMemberDeclarationProvider);
packageDescriptors.put(name, namespaceDescriptor); NamespaceDescriptor oldValue = packageDescriptors.putIfAbsent(name, namespaceDescriptor);
allDescriptors.add(namespaceDescriptor); if (oldValue != null) return oldValue;
registerDescriptor(namespaceDescriptor);
return namespaceDescriptor; return namespaceDescriptor;
} }
@@ -27,6 +27,7 @@ import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
public class LockBasedStorageManager implements StorageManager { public class LockBasedStorageManager implements StorageManager {
@@ -44,6 +45,11 @@ public class LockBasedStorageManager implements StorageManager {
return new ConcurrentHashMap<K, V>(); return new ConcurrentHashMap<K, V>();
} }
@Override
public <E> Collection<E> createConcurrentCollection() {
return new ConcurrentLinkedQueue<E>();
}
@NotNull @NotNull
@Override @Override
public <T> LazyValue<T> createLazyValue(@NotNull Computable<T> computable) { public <T> LazyValue<T> createLazyValue(@NotNull Computable<T> computable) {
@@ -20,12 +20,15 @@ import com.intellij.openapi.util.Computable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import java.util.Collection;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
public interface StorageManager { public interface StorageManager {
@NotNull @NotNull
<K, V> ConcurrentMap<K, V> createConcurrentMap(); <K, V> ConcurrentMap<K, V> createConcurrentMap();
<E> Collection<E> createConcurrentCollection();
@NotNull @NotNull
<T> LazyValue<T> createLazyValue(@NotNull Computable<T> computable); <T> LazyValue<T> createLazyValue(@NotNull Computable<T> computable);