001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.resolve.lazy.storage;
018    
019    import com.google.common.collect.ImmutableMap;
020    import com.intellij.util.containers.ConcurrentWeakValueHashMap;
021    import jet.Function1;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.annotations.TestOnly;
025    import org.jetbrains.jet.lang.diagnostics.Diagnostic;
026    import org.jetbrains.jet.lang.resolve.BindingContext;
027    import org.jetbrains.jet.lang.resolve.BindingTrace;
028    import org.jetbrains.jet.lang.resolve.Diagnostics;
029    import org.jetbrains.jet.storage.LockBasedStorageManager;
030    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
031    import org.jetbrains.jet.storage.MemoizedFunctionToNullable;
032    import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
033    import org.jetbrains.jet.util.slicedmap.WritableSlice;
034    
035    import java.util.Collection;
036    import java.util.concurrent.locks.Lock;
037    
038    public class LockBasedLazyResolveStorageManager extends LockBasedStorageManager implements LazyResolveStorageManager {
039    
040        @Override
041        @NotNull
042        public <K, V> MemoizedFunctionToNotNull<K, V> createWeaklyRetainedMemoizedFunction(
043                @NotNull Function1<K, V> compute
044        ) {
045            return super.createMemoizedFunction(compute, new ConcurrentWeakValueHashMap<K, Object>());
046        }
047    
048        @NotNull
049        @Override
050        public <K, V> MemoizedFunctionToNullable<K, V> createWeaklyRetainedMemoizedFunctionWithNullableValues(
051                @NotNull Function1<K, V> compute
052        ) {
053            return super.createMemoizedFunctionWithNullableValues(compute, new ConcurrentWeakValueHashMap<K, Object>());
054        }
055    
056        @NotNull
057        @Override
058        public BindingTrace createSafeTrace(@NotNull BindingTrace originalTrace) {
059            // It seems safe to have a separate lock for traces:
060            // no other locks will be acquired inside the trace operations
061            return new LockProtectedTrace(lock, originalTrace);
062        }
063    
064        private static class LockProtectedContext implements BindingContext {
065            private final Lock lock;
066            private final BindingContext context;
067    
068            private LockProtectedContext(Lock lock, BindingContext context) {
069                this.lock = lock;
070                this.context = context;
071            }
072    
073            @NotNull
074            @Override
075            public Diagnostics getDiagnostics() {
076                lock.lock();
077                try {
078                    return context.getDiagnostics();
079                }
080                finally {
081                    lock.unlock();
082                }
083            }
084    
085            @Nullable
086            @Override
087            public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
088                lock.lock();
089                try {
090                    return context.get(slice, key);
091                }
092                finally {
093                    lock.unlock();
094                }
095            }
096    
097            @NotNull
098            @Override
099            public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
100                lock.lock();
101                try {
102                    return context.getKeys(slice);
103                }
104                finally {
105                    lock.unlock();
106                }
107            }
108    
109            @NotNull
110            @Override
111            @TestOnly
112            public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
113                lock.lock();
114                try {
115                    return context.getSliceContents(slice);
116                }
117                finally {
118                    lock.unlock();
119                }
120            }
121        }
122    
123        private static class LockProtectedTrace implements BindingTrace {
124            private final Lock lock;
125            private final BindingTrace trace;
126            private final BindingContext context;
127    
128            public LockProtectedTrace(@NotNull Lock lock, @NotNull BindingTrace trace) {
129                this.lock = lock;
130                this.trace = trace;
131                this.context = new LockProtectedContext(lock, trace.getBindingContext());
132            }
133    
134            @Override
135            public BindingContext getBindingContext() {
136                return context;
137            }
138    
139            @Override
140            public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
141                lock.lock();
142                try {
143                    trace.record(slice, key, value);
144                }
145                finally {
146                    lock.unlock();
147                }
148            }
149    
150            @Override
151            public <K> void record(WritableSlice<K, Boolean> slice, K key) {
152                lock.lock();
153                try {
154                    trace.record(slice, key);
155                }
156                finally {
157                    lock.unlock();
158                }
159            }
160    
161            @Override
162            @Nullable
163            public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
164                lock.lock();
165                try {
166                    return trace.get(slice, key);
167                }
168                finally {
169                    lock.unlock();
170                }
171            }
172    
173            @Override
174            @NotNull
175            public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
176                lock.lock();
177                try {
178                    return trace.getKeys(slice);
179                }
180                finally {
181                    lock.unlock();
182                }
183            }
184    
185            @Override
186            public void report(@NotNull Diagnostic diagnostic) {
187                lock.lock();
188                try {
189                    trace.report(diagnostic);
190                }
191                finally {
192                    lock.unlock();
193                }
194            }
195        }
196    }