From 5cf17f089f47238026ebfcb29f53d880242e7803 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 12 Feb 2013 16:00:30 +0400 Subject: [PATCH] Not using flags in NullableLazyValue, no extra objects in MemoizedFunctionToNullable --- .../lazy/storage/LockBasedStorageManager.java | 173 +++++++++--------- 1 file changed, 85 insertions(+), 88 deletions(-) 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 17e3af776f0..5dc35822588 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 @@ -46,28 +46,8 @@ public class LockBasedStorageManager implements StorageManager { public MemoizedFunctionToNotNull createMemoizedFunction( @NotNull final Function compute, @NotNull final ReferenceKind valuesReferenceKind ) { - return new MemoizedFunctionToNotNull() { - private final ConcurrentMap cache = createConcurrentMap(valuesReferenceKind); - - @NotNull - @Override - public V fun(@NotNull final K input) { - V value = cache.get(input); - if (value != null) return value; - - synchronized (lock) { - value = cache.get(input); - if (value != null) return value; - - value = compute.fun(input); - - V oldValue = cache.put(input, value); - assert oldValue == null : "Race condition detected"; - } - - return value; - } - }; + ConcurrentMap map = createConcurrentMap(valuesReferenceKind); + return new MapBasedMemoizedFunctionToNotNull(lock, map, compute); } @NotNull @@ -75,28 +55,8 @@ public class LockBasedStorageManager implements StorageManager { public MemoizedFunctionToNullable createMemoizedFunctionWithNullableValues( @NotNull final Function compute, @NotNull final ReferenceKind valuesReferenceKind ) { - return new MemoizedFunctionToNullable() { - private final ConcurrentMap> cache = createConcurrentMap(valuesReferenceKind); - - @Override - @Nullable - public V fun(@NotNull final K input) { - NullableLazyValue lazyValue = cache.get(input); - if (lazyValue != null) return lazyValue.compute(); - - lazyValue = createNullableLazyValue(new Computable() { - @Override - public V compute() { - return compute.fun(input); - } - }); - - NullableLazyValue oldValue = cache.putIfAbsent(input, lazyValue); - if (oldValue != null) return oldValue.compute(); - - return lazyValue.compute(); - } - }; + ConcurrentMap map = createConcurrentMap(valuesReferenceKind); + return new MapBasedMemoizedFunction(lock, map, compute); } private static ConcurrentMap createConcurrentMap(ReferenceKind referenceKind) { @@ -123,7 +83,7 @@ public class LockBasedStorageManager implements StorageManager { @NotNull @Override public NullableLazyValue createNullableLazyValue(@NotNull Computable computable) { - return new LockBasedNullableLazyValue(lock, computable); + return new LockBasedLazyValue(lock, computable); } @NotNull @@ -131,7 +91,7 @@ public class LockBasedStorageManager implements StorageManager { public NullableLazyValue createNullableLazyValueWithPostCompute( @NotNull Computable computable, @NotNull final Consumer postCompute ) { - return new LockBasedNullableLazyValue(lock, computable) { + return new LockBasedLazyValue(lock, computable) { @Override protected void postCompute(@Nullable T value) { postCompute.consume(value); @@ -147,84 +107,120 @@ public class LockBasedStorageManager implements StorageManager { return new LockProtectedTrace(lock, originalTrace); } - private static class LockBasedNotNullLazyValue implements NotNullLazyValue { + private static class Nulls { + private static final Object NULL_VALUE = new Object(); + + @Nullable + @SuppressWarnings("unchecked") + private static V unescape(@NotNull Object value) { + if (value == NULL_VALUE) return null; + return (V) value; + } + + @NotNull + private static Object escape(@Nullable V value) { + if (value == null) return NULL_VALUE; + return value; + } + } + + private static class LockBasedLazyValue implements NullableLazyValue { private final Object lock; private final Computable computable; @Nullable - private volatile T value; + private volatile Object value = null; - public LockBasedNotNullLazyValue(@NotNull Object lock, @NotNull Computable computable) { + public LockBasedLazyValue(@NotNull Object lock, @NotNull Computable computable) { this.lock = lock; this.computable = computable; } - @NotNull @Override public T compute() { - T _value = value; - if (_value != null) { - return _value; - } + Object _value = value; + if (_value != null) return Nulls.unescape(_value); synchronized (lock) { _value = value; - if (_value == null) { - _value = computable.compute(); - value = _value; - postCompute(_value); - } - return _value; + if (_value != null) return Nulls.unescape(_value); + + T typedValue = computable.compute(); + value = Nulls.escape(typedValue); + + postCompute(typedValue); + + return typedValue; } } - protected void postCompute(@NotNull T value) { + protected void postCompute(T value) { // Doing something in post-compute helps prevent infinite recursion } } - private static class LockBasedNullableLazyValue implements NullableLazyValue { + private static class LockBasedNotNullLazyValue extends LockBasedLazyValue implements NotNullLazyValue { + + public LockBasedNotNullLazyValue(@NotNull Object lock, @NotNull Computable computable) { + super(lock, computable); + } + + @Override + @NotNull + public T compute() { + T result = super.compute(); + assert result != null : "compute() returned null"; + return result; + } + } + + private static class MapBasedMemoizedFunction implements MemoizedFunctionToNullable { private final Object lock; - private final Computable computable; + private final ConcurrentMap cache; + private final Function compute; - private volatile boolean computed = false; - @Nullable - private volatile T value = null; - - public LockBasedNullableLazyValue(@NotNull Object lock, @NotNull Computable computable) { + public MapBasedMemoizedFunction(@NotNull Object lock, @NotNull ConcurrentMap map, @NotNull Function compute) { this.lock = lock; - this.computable = computable; + this.cache = map; + this.compute = compute; } @Override @Nullable - public T compute() { - // NOTE: no local variables used here, because they would not reduce the number of volatile reads/writes - - // We want to guarantee that whenever computed = true, value is not null - // First, read computed, then read value - if (computed) { - return value; - } + public V fun(@NotNull final K input) { + Object value = cache.get(input); + if (value != null) return Nulls.unescape(value); synchronized (lock) { - if (!computed) { - T _value = computable.compute(); + value = cache.get(input); + if (value != null) return Nulls.unescape(value); - // First write value, then write computed - value = _value; - computed = true; + V typedValue = compute.fun(input); - postCompute(_value); + Object oldValue = cache.put(input, Nulls.escape(typedValue)); + assert oldValue == null : "Race condition detected"; - return _value; - } - return value; + return typedValue; } } + } - protected void postCompute(@Nullable T value) { - // Doing something in post-compute helps prevent infinite recursion + private static class MapBasedMemoizedFunctionToNotNull extends MapBasedMemoizedFunction implements MemoizedFunctionToNotNull { + + public MapBasedMemoizedFunctionToNotNull( + @NotNull Object lock, + @NotNull ConcurrentMap map, + @NotNull Function compute + ) { + super(lock, map, compute); + } + + @NotNull + @Override + public V fun(@NotNull K input) { + V result = super.fun(input); + assert result != null : "compute() returned null"; + return result; } } @@ -281,4 +277,5 @@ public class LockBasedStorageManager implements StorageManager { } } } + }