diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java index 9a168659163..28f641d2a9e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/storage/LockBasedStorageManager.java @@ -29,7 +29,8 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.util.slicedmap.ReadOnlySlice; import org.jetbrains.jet.util.slicedmap.WritableSlice; -import org.jetbrains.jet.utils.Nulls; +import org.jetbrains.jet.utils.ExceptionUtils; +import org.jetbrains.jet.utils.WrappedValues; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; @@ -132,18 +133,22 @@ public class LockBasedStorageManager implements StorageManager { @Override public T compute() { Object _value = value; - if (_value != null) return Nulls.unescape(_value); + if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value); synchronized (lock) { _value = value; - if (_value != null) return Nulls.unescape(_value); + if (_value != null) return WrappedValues.unescapeExceptionOrNull(_value); - T typedValue = computable.compute(); - value = Nulls.escape(typedValue); - - postCompute(typedValue); - - return typedValue; + try { + T typedValue = computable.compute(); + value = WrappedValues.escapeNull(typedValue); + postCompute(typedValue); + return typedValue; + } + catch (Throwable throwable) { + value = WrappedValues.escapeThrowable(throwable); + throw ExceptionUtils.rethrow(throwable); + } } } @@ -182,18 +187,25 @@ public class LockBasedStorageManager implements StorageManager { @Nullable public V fun(@NotNull K input) { Object value = cache.get(input); - if (value != null) return Nulls.unescape(value); + if (value != null) return WrappedValues.unescapeExceptionOrNull(value); synchronized (lock) { value = cache.get(input); - if (value != null) return Nulls.unescape(value); + if (value != null) return WrappedValues.unescapeExceptionOrNull(value); - V typedValue = compute.fun(input); + try { + V typedValue = compute.fun(input); + Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue)); + assert oldValue == null : "Race condition detected"; - Object oldValue = cache.put(input, Nulls.escape(typedValue)); - assert oldValue == null : "Race condition detected"; + return typedValue; + } + catch (Throwable throwable) { + Object oldValue = cache.put(input, WrappedValues.escapeThrowable(throwable)); + assert oldValue == null : "Race condition detected"; - return typedValue; + throw ExceptionUtils.rethrow(throwable); + } } } } diff --git a/compiler/util/src/org/jetbrains/jet/utils/ExceptionUtils.java b/compiler/util/src/org/jetbrains/jet/utils/ExceptionUtils.java index 7bab6725705..0bd9ce2f216 100644 --- a/compiler/util/src/org/jetbrains/jet/utils/ExceptionUtils.java +++ b/compiler/util/src/org/jetbrains/jet/utils/ExceptionUtils.java @@ -20,6 +20,9 @@ import java.io.Closeable; public class ExceptionUtils { + private ExceptionUtils() { + } + /** * Translate exception to unchecked exception. * @@ -43,7 +46,7 @@ public class ExceptionUtils { if (closeable != null) { try { closeable.close(); - } catch (Throwable e) { + } catch (Throwable ignored) { } } } diff --git a/compiler/util/src/org/jetbrains/jet/utils/NullableMemoizedFunction.java b/compiler/util/src/org/jetbrains/jet/utils/NullableMemoizedFunction.java index 2a49b2ab30d..867944d6ced 100644 --- a/compiler/util/src/org/jetbrains/jet/utils/NullableMemoizedFunction.java +++ b/compiler/util/src/org/jetbrains/jet/utils/NullableMemoizedFunction.java @@ -50,11 +50,11 @@ public abstract class NullableMemoizedFunction implements NullableFunction @Nullable public V fun(@NotNull K input) { Object value = cache.get(input); - if (value != null) return Nulls.unescape(value); + if (value != null) return WrappedValues.unescapeNull(value); V typedValue = compute(input); - Object oldValue = cache.put(input, Nulls.escape(typedValue)); + Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue)); assert oldValue == null : "Race condition detected"; return typedValue; diff --git a/compiler/util/src/org/jetbrains/jet/utils/Nulls.java b/compiler/util/src/org/jetbrains/jet/utils/WrappedValues.java similarity index 52% rename from compiler/util/src/org/jetbrains/jet/utils/Nulls.java rename to compiler/util/src/org/jetbrains/jet/utils/WrappedValues.java index b5ce971d636..c345808d833 100644 --- a/compiler/util/src/org/jetbrains/jet/utils/Nulls.java +++ b/compiler/util/src/org/jetbrains/jet/utils/WrappedValues.java @@ -19,19 +19,49 @@ package org.jetbrains.jet.utils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class Nulls { +public class WrappedValues { private static final Object NULL_VALUE = new Object(); + private final static class ThrowableWrapper { + private final Throwable throwable; + + private ThrowableWrapper(@NotNull Throwable throwable) { + this.throwable = throwable; + } + + @NotNull + public Throwable getThrowable() { + return throwable; + } + } + + private WrappedValues() { + } + @Nullable @SuppressWarnings("unchecked") - public static V unescape(@NotNull Object value) { + public static V unescapeNull(@NotNull Object value) { if (value == NULL_VALUE) return null; return (V) value; } @NotNull - public static Object escape(@Nullable V value) { + public static Object escapeNull(@Nullable V value) { if (value == null) return NULL_VALUE; return value; } + + @NotNull + public static Object escapeThrowable(@NotNull Throwable throwable) { + return new ThrowableWrapper(throwable); + } + + @Nullable + public static V unescapeExceptionOrNull(@NotNull Object value) { + if (value instanceof ThrowableWrapper) { + throw ExceptionUtils.rethrow(((ThrowableWrapper) value).getThrowable()); + } + + return unescapeNull(value); + } }