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 }