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.storage;
018
019 import com.google.common.collect.ImmutableMap;
020 import com.intellij.util.containers.ConcurrentWeakValueHashMap;
021 import kotlin.Function0;
022 import kotlin.Function1;
023 import kotlin.Unit;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.annotations.TestOnly;
027 import org.jetbrains.jet.lang.diagnostics.Diagnostic;
028 import org.jetbrains.jet.lang.resolve.BindingContext;
029 import org.jetbrains.jet.lang.resolve.BindingTrace;
030 import org.jetbrains.jet.lang.resolve.Diagnostics;
031 import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
032 import org.jetbrains.jet.util.slicedmap.WritableSlice;
033
034 import java.util.Collection;
035 import java.util.concurrent.locks.Lock;
036
037 // This class is kept under the same package as LockBasedStorageManager to get access to its protected members
038 // Otherwise wed have to expose the lock which is worse than have such a hackish class placement
039 public class LockBasedLazyResolveStorageManager implements LazyResolveStorageManager {
040
041 private final LockBasedStorageManager storageManager;
042
043 public LockBasedLazyResolveStorageManager(@NotNull LockBasedStorageManager storageManager) {
044 this.storageManager = storageManager;
045 }
046
047 @Override
048 @NotNull
049 public <K, V> MemoizedFunctionToNotNull<K, V> createWeaklyRetainedMemoizedFunction(
050 @NotNull Function1<K, V> compute
051 ) {
052 return storageManager.createMemoizedFunction(compute, new ConcurrentWeakValueHashMap<K, Object>());
053 }
054
055 @NotNull
056 @Override
057 public <K, V> MemoizedFunctionToNullable<K, V> createWeaklyRetainedMemoizedFunctionWithNullableValues(
058 @NotNull Function1<K, V> compute
059 ) {
060 return storageManager.createMemoizedFunctionWithNullableValues(compute, new ConcurrentWeakValueHashMap<K, Object>());
061 }
062
063 @NotNull
064 @Override
065 public BindingTrace createSafeTrace(@NotNull BindingTrace originalTrace) {
066 // It seems safe to have a separate lock for traces:
067 // no other locks will be acquired inside the trace operations
068 return new LockProtectedTrace(storageManager.lock, originalTrace);
069 }
070
071 @NotNull
072 @Override
073 public <K, V> MemoizedFunctionToNotNull<K, V> createMemoizedFunction(@NotNull Function1<? super K, ? extends V> compute) {
074 return storageManager.createMemoizedFunction(compute);
075 }
076
077 @NotNull
078 @Override
079 public <K, V> MemoizedFunctionToNullable<K, V> createMemoizedFunctionWithNullableValues(@NotNull Function1<? super K, ? extends V> compute) {
080 return storageManager.createMemoizedFunctionWithNullableValues(compute);
081 }
082
083 @NotNull
084 @Override
085 public <T> NotNullLazyValue<T> createLazyValue(@NotNull Function0<? extends T> computable) {
086 return storageManager.createLazyValue(computable);
087 }
088
089 @NotNull
090 @Override
091 public <T> NotNullLazyValue<T> createRecursionTolerantLazyValue(
092 @NotNull Function0<? extends T> computable,
093 @NotNull T onRecursiveCall
094 ) {
095 return storageManager.createRecursionTolerantLazyValue(computable, onRecursiveCall);
096 }
097
098 @NotNull
099 @Override
100 public <T> NotNullLazyValue<T> createLazyValueWithPostCompute(
101 @NotNull Function0<? extends T> computable,
102 @Nullable Function1<? super Boolean, ? extends T> onRecursiveCall,
103 @NotNull Function1<? super T, ? extends Unit> postCompute
104 ) {
105 return storageManager.createLazyValueWithPostCompute(computable, onRecursiveCall, postCompute);
106 }
107
108 @NotNull
109 @Override
110 public <T> NullableLazyValue<T> createNullableLazyValue(@NotNull Function0<? extends T> computable) {
111 return storageManager.createNullableLazyValue(computable);
112 }
113
114 @NotNull
115 @Override
116 public <T> NullableLazyValue<T> createRecursionTolerantNullableLazyValue(
117 @NotNull Function0<? extends T> computable,
118 T onRecursiveCall
119 ) {
120 return storageManager.createRecursionTolerantNullableLazyValue(computable, onRecursiveCall);
121 }
122
123 @NotNull
124 @Override
125 public <T> NullableLazyValue<T> createNullableLazyValueWithPostCompute(
126 @NotNull Function0<? extends T> computable,
127 @NotNull Function1<? super T, ? extends Unit> postCompute
128 ) {
129 return storageManager.createNullableLazyValueWithPostCompute(computable, postCompute);
130 }
131
132 @Override
133 public <T> T compute(@NotNull Function0<? extends T> computable) {
134 return storageManager.compute(computable);
135 }
136
137 private static class LockProtectedContext implements BindingContext {
138 private final Lock lock;
139 private final BindingContext context;
140
141 private LockProtectedContext(Lock lock, BindingContext context) {
142 this.lock = lock;
143 this.context = context;
144 }
145
146 @NotNull
147 @Override
148 public Diagnostics getDiagnostics() {
149 lock.lock();
150 try {
151 return context.getDiagnostics();
152 }
153 finally {
154 lock.unlock();
155 }
156 }
157
158 @Nullable
159 @Override
160 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
161 lock.lock();
162 try {
163 return context.get(slice, key);
164 }
165 finally {
166 lock.unlock();
167 }
168 }
169
170 @NotNull
171 @Override
172 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
173 lock.lock();
174 try {
175 return context.getKeys(slice);
176 }
177 finally {
178 lock.unlock();
179 }
180 }
181
182 @NotNull
183 @Override
184 @TestOnly
185 public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> slice) {
186 lock.lock();
187 try {
188 return context.getSliceContents(slice);
189 }
190 finally {
191 lock.unlock();
192 }
193 }
194 }
195
196 private static class LockProtectedTrace implements BindingTrace {
197 private final Lock lock;
198 private final BindingTrace trace;
199 private final BindingContext context;
200
201 public LockProtectedTrace(@NotNull Lock lock, @NotNull BindingTrace trace) {
202 this.lock = lock;
203 this.trace = trace;
204 this.context = new LockProtectedContext(lock, trace.getBindingContext());
205 }
206
207 @NotNull
208 @Override
209 public BindingContext getBindingContext() {
210 return context;
211 }
212
213 @Override
214 public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
215 lock.lock();
216 try {
217 trace.record(slice, key, value);
218 }
219 finally {
220 lock.unlock();
221 }
222 }
223
224 @Override
225 public <K> void record(WritableSlice<K, Boolean> slice, K key) {
226 lock.lock();
227 try {
228 trace.record(slice, key);
229 }
230 finally {
231 lock.unlock();
232 }
233 }
234
235 @Override
236 @Nullable
237 public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
238 lock.lock();
239 try {
240 return trace.get(slice, key);
241 }
242 finally {
243 lock.unlock();
244 }
245 }
246
247 @Override
248 @NotNull
249 public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
250 lock.lock();
251 try {
252 return trace.getKeys(slice);
253 }
254 finally {
255 lock.unlock();
256 }
257 }
258
259 @Override
260 public void report(@NotNull Diagnostic diagnostic) {
261 lock.lock();
262 try {
263 trace.report(diagnostic);
264 }
265 finally {
266 lock.unlock();
267 }
268 }
269 }
270 }