You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/07/10 16:33:44 UTC

[groovy] branch GROOVY-9631 updated (2d8a698 -> b055d74)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY-9631
in repository https://gitbox.apache.org/repos/asf/groovy.git.


 discard 2d8a698  Hold the value with hard reference
 discard cd52ea0  Tweak javadoc of `ManagedConcurrentMap`
 discard 6da17e0  Avoid wasting heap to allocate memory for deprecated data structure
    omit f9acadb  Apply bridging
    omit 8643cbf  Add `GroovyClassValuePreJava7` back for binary compatibility
    omit f9ed342  Add deprecated members of `ManagedConcurrentMap` back for binary compatibility
    omit 20da422  Add `AbstractConcurrentMap` and `AbstractConcurrentMapBase` back for binary compatibility
    omit 519ef9b  Add `getAndPut` back for binary compatibility
    omit e36a3ee  Tweak javadoc of `ManagedConcurrentMap`
    omit 592acd6  Rename `getAndPut` to `getOrPut`
    omit fc931d6  GROOVY-9631: Replace legacy data structure with Java collection
     new b055d74  GROOVY-9631: Replace legacy data structure with Java collection

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (2d8a698)
            \
             N -- N -- N   refs/heads/GROOVY-9631 (b055d74)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:


[groovy] 01/01: GROOVY-9631: Replace legacy data structure with Java collection

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9631
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit b055d74ac87564371804306ea6642a0547b0b7c2
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Jul 11 00:33:07 2020 +0800

    GROOVY-9631: Replace legacy data structure with Java collection
---
 build.gradle                                       |   1 +
 src/main/java/groovy/util/ProxyGenerator.java      |   2 +-
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |   2 +-
 .../codehaus/groovy/control/ResolveVisitor.java    |   2 +-
 .../reflection/GroovyClassValuePreJava7.java       |   3 +-
 .../groovy/runtime/memoize/CommonCache.java        |   2 +-
 .../runtime/memoize/ConcurrentCommonCache.java     |   2 +-
 .../codehaus/groovy/runtime/memoize/LRUCache.java  |   2 +-
 .../codehaus/groovy/runtime/memoize/Memoize.java   |   4 +-
 .../groovy/runtime/memoize/MemoizeCache.java       |  19 ++-
 .../groovy/runtime/memoize/StampedCommonCache.java |   4 +-
 .../runtime/memoize/UnlimitedConcurrentCache.java  |   2 +-
 .../metaclass/ThreadManagedMetaBeanProperty.java   |   2 +-
 .../stc/AbstractExtensionMethodCache.java          |   2 +-
 .../groovy/util/AbstractConcurrentMap.java         |   6 +-
 .../groovy/util/AbstractConcurrentMapBase.java     |   9 +-
 .../codehaus/groovy/util/ManagedConcurrentMap.java | 189 ++++++++++++++++++++-
 .../groovy/vmplugin/v8/CacheableCallSite.java      |   2 +-
 .../groovy/runtime/memoize/CommonCacheTest.java    |   2 +-
 .../runtime/memoize/ConcurrentCommonCacheTest.java |   4 +-
 .../runtime/memoize/StampedCommonCacheTest.java    |   4 +-
 .../memoize/UnlimitedConcurrentCacheTest.java      |   2 +-
 .../util/AbstractConcurrentMapSegmentTest.groovy   |   1 +
 .../groovy/util/ManagedConcurrentMapTest.groovy    |   2 -
 24 files changed, 236 insertions(+), 34 deletions(-)

diff --git a/build.gradle b/build.gradle
index 7f2f1f2..ef87e8e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -272,6 +272,7 @@ compileJava {
             arg(value: "${sourceSets.main.java.outputDir.canonicalPath}/org/codehaus/groovy/runtime/StringGroovyMethods.class")
             arg(value: "${sourceSets.main.java.outputDir.canonicalPath}/org/codehaus/groovy/classgen/Verifier.class")
             arg(value: "${sourceSets.main.java.outputDir.canonicalPath}/org/codehaus/groovy/ast/tools/GeneralUtils.class")
+            arg(value: "${sourceSets.main.java.outputDir.canonicalPath}/org/codehaus/groovy/util/AbstractConcurrentMap.class")
         }
         ant.echo('Bridger (groovy): ' + ant.properties.stdout)
     }
diff --git a/src/main/java/groovy/util/ProxyGenerator.java b/src/main/java/groovy/util/ProxyGenerator.java
index 06d6a2a..02b448c 100644
--- a/src/main/java/groovy/util/ProxyGenerator.java
+++ b/src/main/java/groovy/util/ProxyGenerator.java
@@ -227,7 +227,7 @@ public class ProxyGenerator {
         CacheKey key = new CacheKey(base, useDelegate ? delegateClass : Object.class, keys, intfs, emptyMethods, useDelegate);
         final Class b = base;
 
-        return (ProxyGeneratorAdapter) adapterCache.getAndPut(
+        return (ProxyGeneratorAdapter) adapterCache.getOrPut(
                 key,
                 k -> new ProxyGeneratorAdapter(closureMap, b, intfs, useDelegate
                         ? delegateClass.getClassLoader()
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index edff680..da06f6d 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -695,7 +695,7 @@ public class GenericsUtils {
             return findParameterizedType(genericsClass, actualType, tryToFindExactType);
         }
 
-        SoftReference<ClassNode> sr = PARAMETERIZED_TYPE_CACHE.getAndPut(new ParameterizedTypeCacheKey(genericsClass, actualType), key -> new SoftReference<>(findParameterizedType(key.getGenericsClass(), key.getActualType(), tryToFindExactType)));
+        SoftReference<ClassNode> sr = PARAMETERIZED_TYPE_CACHE.getOrPut(new ParameterizedTypeCacheKey(genericsClass, actualType), key -> new SoftReference<>(findParameterizedType(key.getGenericsClass(), key.getActualType(), tryToFindExactType)));
 
         return null == sr ? null : sr.get();
     }
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 4395dc8..6a487b5 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -657,7 +657,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 type.setRedirect(tmp.redirect());
 
                 if (DEFAULT_IMPORTS == packagePrefixes) { // Only the non-cached type and packages should be cached
-                    Set<String> packagePrefixSet = DEFAULT_IMPORT_CLASS_AND_PACKAGES_CACHE.getAndPut(typeName, key -> new HashSet<>(2));
+                    Set<String> packagePrefixSet = DEFAULT_IMPORT_CLASS_AND_PACKAGES_CACHE.getOrPut(typeName, key -> new HashSet<>(2));
                     packagePrefixSet.add(packagePrefix);
                 }
 
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
index 02f893c..1e4db24 100644
--- a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -28,6 +28,7 @@ import org.codehaus.groovy.util.ReferenceBundle;
  *
  * @param <T>
  */
+@Deprecated
 class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
 	private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
 
@@ -93,7 +94,7 @@ class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
 	@Override
 	public T get(Class<?> type) {
 		// the value isn't use in the getOrPut call - see the EntryWithValue constructor above
-		T value = ((EntryWithValue)map.getOrPut(type, null)).getValue();
+		T value = map.getOrPut(type, null).get();
 		//all entries are guaranteed to be EntryWithValue. Value can only be null if computeValue returns null
 		return value;
 	}
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/CommonCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/CommonCache.java
index 0f7fb75..92d90d6 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/CommonCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/CommonCache.java
@@ -124,7 +124,7 @@ public class CommonCache<K, V> implements EvictableCache<K, V>, ValueConvertable
      * {@inheritDoc}
      */
     @Override
-    public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    public V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         return getAndPut(key, valueProvider, true);
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java
index ace4ae6..b2e608d 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCache.java
@@ -109,7 +109,7 @@ public class ConcurrentCommonCache<K, V> implements EvictableCache<K, V>, ValueC
      * {@inheritDoc}
      */
     @Override
-    public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    public V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         return getAndPut(key, valueProvider, true);
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/LRUCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/LRUCache.java
index 75b134c..9e9b361 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/LRUCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/LRUCache.java
@@ -59,7 +59,7 @@ public final class LRUCache<K, V> implements MemoizeCache<K, V> {
      * @param valueProvider provide the value if the associated value not found
      */
     @Override
-    public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    public V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         return map.computeIfAbsent(key, valueProvider::provide);
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/Memoize.java b/src/main/java/org/codehaus/groovy/runtime/memoize/Memoize.java
index 21608df..9956fd0 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/Memoize.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/Memoize.java
@@ -133,7 +133,7 @@ public abstract class Memoize {
         @Override
         public V call(final Object... args) {
             final Object key = generateKey(args);
-            Object result = cache.getAndPut(key, k -> {
+            Object result = cache.getOrPut(key, k -> {
                 Object r = closure.call(args);
                 //noinspection GroovyConditionalCanBeElvis
                 return r != null ? r : MEMOIZE_NULL;
@@ -164,7 +164,7 @@ public abstract class Memoize {
             if (queue.poll() != null) cleanUpNullReferences(cache, queue);  // if something has been evicted, do a clean-up
             final Object key = generateKey(args);
 
-            SoftReference reference = (SoftReference) cache.getAndPut(key, k -> {
+            SoftReference reference = (SoftReference) cache.getOrPut(key, k -> {
                 Object r = closure.call(args);
 
                 return null != r ? new SoftReference<Object>(r, queue) : new SoftReference<Object>(MEMOIZE_NULL);
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
index c525919..957833b 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/MemoizeCache.java
@@ -44,11 +44,11 @@ public interface MemoizeCache<K, V> {
      * Try to get the value from cache.
      * If not found, create the value by {@link ValueProvider} and put it into the cache, at last return the value.
      *
-     * @param key
+     * @param key the key to look up
      * @param valueProvider provide the value if the associated value not found
      * @return the cached value
      */
-    default V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    default V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         V value = this.get(key);
 
         if (null == value) {
@@ -60,6 +60,21 @@ public interface MemoizeCache<K, V> {
     }
 
     /**
+     *
+     * Try to get the value from cache.
+     * If not found, create the value by {@link ValueProvider} and put it into the cache, at last return the value.
+     *
+     * @param key the key to look up
+     * @param valueProvider provide the value if the associated value not found
+     * @return the cached value
+     * @deprecated Use {@link #getOrPut(Object, ValueProvider)} instead
+     */
+    @Deprecated
+    default V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+        return getOrPut(key, valueProvider);
+    }
+
+    /**
      * Invoked when some of the held SoftReferences have been evicted by the garbage collector and so should be removed from the cache.
      * The implementation must ensure that concurrent invocations of all methods on the cache may occur from other threads
      * and thus should protect any shared resources.
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/StampedCommonCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/StampedCommonCache.java
index 1b1da7a..e7b88bb 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/StampedCommonCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/StampedCommonCache.java
@@ -28,7 +28,7 @@ import java.util.concurrent.locks.StampedLock;
 /**
  * Represents a simple key-value cache, which is thread safe and backed by a {@link Map} instance.
  * StampedCommonCache has better performance than {@link ConcurrentCommonCache},
- * but it is not reentrant, in other words, <b>it may cause deadlock</b> if {@link #getAndPut(Object, MemoizeCache.ValueProvider)}
+ * but it is not reentrant, in other words, <b>it may cause deadlock</b> if {@link #getOrPut(Object, MemoizeCache.ValueProvider)}
  * or {@link #getAndPut(Object, MemoizeCache.ValueProvider, boolean)} is called recursively:
  * readlock -&gt; upgrade to writelock -&gt; readlock (fails to get and waits forever)
  *
@@ -111,7 +111,7 @@ public class StampedCommonCache<K, V> implements EvictableCache<K, V>, ValueConv
      * {@inheritDoc}
      */
     @Override
-    public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    public V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         return getAndPut(key, valueProvider, true);
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java b/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
index a813620..21555c8 100644
--- a/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
+++ b/src/main/java/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCache.java
@@ -191,7 +191,7 @@ public final class UnlimitedConcurrentCache<K, V> implements EvictableCache<K, V
      * @return the cached value
      */
     @Override
-    public V getAndPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
+    public V getOrPut(K key, ValueProvider<? super K, ? extends V> valueProvider) {
         return map.computeIfAbsent(key, valueProvider::provide);
     }
 
diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
index 5074908..b6ac4cf 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
@@ -176,7 +176,7 @@ public class ThreadManagedMetaBeanProperty extends MetaBeanProperty {
            * @see groovy.lang.MetaMethod#invoke(java.lang.Object, java.lang.Object[])
            */
         public Object invoke(Object object, Object[] arguments) {
-            return instance2Prop.getOrPut(object, getInitialValue()).getValue();
+            return instance2Prop.computeIfAbsent(object, k -> getInitialValue());
         }
     }
 
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/AbstractExtensionMethodCache.java b/src/main/java/org/codehaus/groovy/transform/stc/AbstractExtensionMethodCache.java
index df8f8b6..1445732 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/AbstractExtensionMethodCache.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/AbstractExtensionMethodCache.java
@@ -48,7 +48,7 @@ public abstract class AbstractExtensionMethodCache {
     final EvictableCache<ClassLoader, Map<String, List<MethodNode>>> cache = new StampedCommonCache<>(new WeakHashMap<>());
 
     public Map<String, List<MethodNode>> get(ClassLoader loader) {
-        return cache.getAndPut(loader, this::getMethodsFromClassLoader);
+        return cache.getOrPut(loader, this::getMethodsFromClassLoader);
     }
 
     private Map<String, List<MethodNode>> getMethodsFromClassLoader(ClassLoader classLoader) {
diff --git a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
index 6168877..0c5557f 100644
--- a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
+++ b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMap.java
@@ -18,7 +18,9 @@
  */
 package org.codehaus.groovy.util;
 
+@Deprecated
 public abstract class AbstractConcurrentMap<K, V> extends AbstractConcurrentMapBase {
+    protected AbstractConcurrentMap() {}
 
     public AbstractConcurrentMap(Object segmentInfo) {
         super(segmentInfo);
@@ -33,7 +35,7 @@ public abstract class AbstractConcurrentMap<K, V> extends AbstractConcurrentMapB
         return (V) segmentFor(hash).get(key, hash);
     }
 
-    public Entry<K,V> getOrPut(K key, V value) {
+    public Entry<K,V> getOrPut$$bridge(K key, V value) {
         int hash = hash(key);
         return segmentFor(hash).getOrPut(key, hash, value);
     }
@@ -43,7 +45,7 @@ public abstract class AbstractConcurrentMap<K, V> extends AbstractConcurrentMapB
         segmentFor(hash).put(key, hash, value);
     }
 
-    public void remove(K key) {
+    public void remove$$bridge(K key) {
         int hash = hash(key);
         segmentFor(hash).remove(key, hash);
     }
diff --git a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
index 01f84af..e21de26 100644
--- a/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
+++ b/src/main/java/org/codehaus/groovy/util/AbstractConcurrentMapBase.java
@@ -21,13 +21,16 @@ package org.codehaus.groovy.util;
 import java.util.Collection;
 import java.util.LinkedList;
 
+@Deprecated
 public abstract class AbstractConcurrentMapBase {
     protected static final int MAXIMUM_CAPACITY = 1 << 30;
     static final int MAX_SEGMENTS = 1 << 16;
     static final int RETRIES_BEFORE_LOCK = 2;
-    final int segmentMask;
-    final int segmentShift;
-    protected final Segment[] segments;
+    int segmentMask;
+    int segmentShift;
+    protected Segment[] segments;
+
+    protected AbstractConcurrentMapBase() {}
 
     public AbstractConcurrentMapBase(Object segmentInfo) {
         int sshift = 0;
diff --git a/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java b/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
index d1cf760..9d2371a 100644
--- a/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
+++ b/src/main/java/org/codehaus/groovy/util/ManagedConcurrentMap.java
@@ -18,20 +18,199 @@
  */
 package org.codehaus.groovy.util;
 
-public class ManagedConcurrentMap<K,V> extends AbstractConcurrentMap<K,V> {
-    protected ReferenceBundle bundle;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Represents a concurrent map based on {@link ConcurrentHashMap}.
+ * When the value is collected by JVM, the entry will be removed too.
+ * <p />
+ * Note: {@code extends AbstractConcurrentMap<K, V>} is just for binary compatibility
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ */
+public class ManagedConcurrentMap<K, V> extends AbstractConcurrentMap<K, V> {
+    private final ConcurrentMap<IdentityKey<K>, ManagedValue<V>> internalMap = new ConcurrentHashMap<>();
+    private final ReferenceBundle bundle;
+
     public ManagedConcurrentMap(ReferenceBundle bundle) {
-        super(bundle);
+        if (bundle == null) throw new IllegalArgumentException("bundle must not be null");
         this.bundle = bundle;
-        if (bundle==null) throw new IllegalArgumentException("bundle must not be null");
     }
 
+    /**
+     * Returns the value stored for the given key at the point of call.
+     *
+     * @param key a non null key
+     * @return the value stored in the map for the given key
+     */
+    public V get(Object key) {
+        return toValue(internalMap.get(new IdentityKey(key)));
+    }
+
+    /**
+     * Sets a new value for a given key. an older value is overwritten.
+     *
+     * @param key   a non null key
+     * @param value the new value
+     */
+    public void put(final K key, V value) {
+        final IdentityKey<K> k = new IdentityKey<K>(key);
+        internalMap.put(k, toManagedValue(k, value));
+    }
+
+    /**
+     * If the key is absent, put the key and value into the map and return the value.
+     * Or return the key related value directly
+     *
+     * @param key the key to look up
+     * @param mappingFunction providing the value if the key is absent
+     * @return the key related value
+     */
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        return toValue(getOrPut(key, mappingFunction));
+    }
+
+    /**
+     * If the key is absent, put the key and value into the map and return the value.
+     * Or return the key related {@link ManagedReference} instance, which wraps the value
+     *
+     * @param key the key to look up
+     * @param value the value to put if the key is absent
+     * @return the {@link ManagedReference} instance wrapping the value
+     */
+    public ManagedValue<V> getOrPut(K key, V value) {
+        return getOrPut(key, k -> value);
+    }
+
+    private ManagedValue<V> getOrPut(K key, Function<? super K, ? extends V> mappingFunction) {
+        final IdentityKey<K> key1 = new IdentityKey<K>(key);
+        return internalMap.computeIfAbsent(key1, k -> toManagedValue(key1, mappingFunction.apply(k.key)));
+    }
+
+    /**
+     * Remove the key related entry
+     *
+     * @param key the key to look up
+     * @return the removed entry related value
+     */
+    public V remove(Object key) {
+        return toValue(internalMap.remove(new IdentityKey(key)));
+    }
+
+    /**
+     * Returns map values
+     */
+    public Collection<V> values() {
+        return internalMap.values().stream().map(this::toValue).collect(Collectors.toList());
+    }
+
+    /**
+     * Returns map size
+     */
+    public int size() {
+        return internalMap.size();
+    }
+
+    private V toValue(ManagedValue<V> mv) {
+        if (null == mv) return null;
+
+        return mv.value;
+    }
+
+    private ManagedValue<V> toManagedValue(IdentityKey<K> key, V value) {
+        final ManagedValue<V> mv = new ManagedValue<V>(value);
+        ManagedReference<V> ref = new ManagedReference<V>(bundle, value) {
+            @Override
+            public void finalizeReference() {
+                internalMap.remove(key, mv);
+                super.finalizeReference();
+            }
+        };
+        mv.setManagedReference(ref);
+
+        return mv;
+    }
+
+    /**
+     * Represents identity key of {@link ManagedConcurrentMap}
+     *
+     * @param <K> the key type
+     * @since 4.0.0
+     */
+    private static class IdentityKey<K> {
+        private final K key;
+
+        private IdentityKey(K key) {
+            this.key = key;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof IdentityKey)) return false;
+            return key == ((IdentityKey<?>) o).key;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = System.identityHashCode(key);
+            hash += (hash << 15) ^ 0xffffcd7d;
+            hash ^= (hash >>> 10);
+            hash += (hash << 3);
+            hash ^= (hash >>> 6);
+            hash += (hash << 2) + (hash << 14);
+            hash ^= (hash >>> 16);
+            return hash;
+        }
+    }
+
+    /**
+     * Represents the managed value
+     * @param <V> the value type
+     * @since 4.0.0
+     */
+    public static class ManagedValue<V> implements Finalizable {
+        private ManagedReference<V> mr;
+        private V value;
+
+        private ManagedValue(V value) {
+            this.value = value;
+        }
+
+        private void setManagedReference(ManagedReference<V> mr) {
+            this.mr = mr;
+        }
+
+        public V get() {
+            return value;
+        }
+
+        public void clear() {
+            this.value = null;
+            mr.clear();
+        }
+
+        @Override
+        public void finalizeReference() {
+            this.value = null;
+            mr.finalizeReference();
+        }
+    }
+
+    // ------------------------- the following members are deprecated ---------------------------
+    @Deprecated
     protected Segment<K,V> createSegment(Object segmentInfo, int cap) {
         ReferenceBundle bundle = (ReferenceBundle) segmentInfo;
         if (bundle==null) throw new IllegalArgumentException("bundle must not be null");
         return new ManagedConcurrentMap.Segment<K,V>(bundle, cap);
     }
 
+    @Deprecated
     public static class Segment<K,V> extends AbstractConcurrentMap.Segment<K,V>{
         private static final long serialVersionUID = 2742952509311037869L;
         protected final ReferenceBundle bundle;
@@ -48,6 +227,7 @@ public class ManagedConcurrentMap<K,V> extends AbstractConcurrentMap<K,V> {
         }
     }
 
+    @Deprecated
     public static class Entry<K,V> extends ManagedReference<K> implements AbstractConcurrentMap.Entry<K,V> {
         private final Segment segment;
         private final int hash;
@@ -92,6 +272,7 @@ public class ManagedConcurrentMap<K,V> extends AbstractConcurrentMap<K,V> {
         }
     }
 
+    @Deprecated
     public static class EntryWithValue<K,V> extends Entry<K,V> {
         private V value;
 
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
index a6e4c4c..d1befe7 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
@@ -45,7 +45,7 @@ public class CacheableCallSite extends MutableCallSite {
     }
 
     public MethodHandleWrapper getAndPut(String className, MemoizeCache.ValueProvider<? super String, ? extends MethodHandleWrapper> valueProvider) {
-        final MethodHandleWrapper result = cache.getAndPut(className, valueProvider);
+        final MethodHandleWrapper result = cache.getOrPut(className, valueProvider);
         final MethodHandleWrapper lhmh = latestHitMethodHandleWrapper;
 
         if (lhmh == result) {
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java
index 2223e54..2b056aa 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java
+++ b/src/test/org/codehaus/groovy/runtime/memoize/CommonCacheTest.java
@@ -65,7 +65,7 @@ public class CommonCacheTest {
         Assert.assertEquals("Chinese", sc.getAndPut("language", vp,false));
         Assert.assertNull(sc.get("language"));
 
-        Assert.assertEquals("Chinese", sc.getAndPut("language", vp));
+        Assert.assertEquals("Chinese", sc.getOrPut("language", vp));
         Assert.assertEquals("Chinese", sc.get("language"));
     }
 
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java
index efbb054..3769aa0 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java
+++ b/src/test/org/codehaus/groovy/runtime/memoize/ConcurrentCommonCacheTest.java
@@ -66,7 +66,7 @@ public class ConcurrentCommonCacheTest {
         Assert.assertEquals("Chinese", sc.getAndPut("language", vp,false));
         Assert.assertNull(sc.get("language"));
 
-        Assert.assertEquals("Chinese", sc.getAndPut("language", vp));
+        Assert.assertEquals("Chinese", sc.getOrPut("language", vp));
         Assert.assertEquals("Chinese", sc.get("language"));
     }
 
@@ -213,7 +213,7 @@ public class ConcurrentCommonCacheTest {
                 try {
                     countDownLatch.await();
 
-                    m.getAndPut(123, k -> cnt.getAndIncrement());
+                    m.getOrPut(123, k -> cnt.getAndIncrement());
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } finally {
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/StampedCommonCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/StampedCommonCacheTest.java
index 2fc6ff6..ca3391c 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/StampedCommonCacheTest.java
+++ b/src/test/org/codehaus/groovy/runtime/memoize/StampedCommonCacheTest.java
@@ -66,7 +66,7 @@ public class StampedCommonCacheTest {
         Assert.assertEquals("Chinese", sc.getAndPut("language", vp,false));
         Assert.assertNull(sc.get("language"));
 
-        Assert.assertEquals("Chinese", sc.getAndPut("language", vp));
+        Assert.assertEquals("Chinese", sc.getOrPut("language", vp));
         Assert.assertEquals("Chinese", sc.get("language"));
     }
 
@@ -213,7 +213,7 @@ public class StampedCommonCacheTest {
                 try {
                     countDownLatch.await();
 
-                    m.getAndPut(123, k -> cnt.getAndIncrement());
+                    m.getOrPut(123, k -> cnt.getAndIncrement());
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } finally {
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java b/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
index ab5d4ad..e8f56ba 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
+++ b/src/test/org/codehaus/groovy/runtime/memoize/UnlimitedConcurrentCacheTest.java
@@ -64,7 +64,7 @@ public class UnlimitedConcurrentCacheTest {
         EvictableCache.ValueProvider vp =
                 (EvictableCache.ValueProvider<String, String>) key -> "Chinese";
 
-        Assert.assertEquals("Chinese", sc.getAndPut("language", vp));
+        Assert.assertEquals("Chinese", sc.getOrPut("language", vp));
         Assert.assertEquals("Chinese", sc.get("language"));
     }
 
diff --git a/src/test/org/codehaus/groovy/util/AbstractConcurrentMapSegmentTest.groovy b/src/test/org/codehaus/groovy/util/AbstractConcurrentMapSegmentTest.groovy
index 4f275f5..1706715 100644
--- a/src/test/org/codehaus/groovy/util/AbstractConcurrentMapSegmentTest.groovy
+++ b/src/test/org/codehaus/groovy/util/AbstractConcurrentMapSegmentTest.groovy
@@ -21,6 +21,7 @@ package org.codehaus.groovy.util
 import org.junit.Before
 import org.junit.Test
 
+@Deprecated
 class AbstractConcurrentMapSegmentTest {
     private static final Integer INITIAL_SEGMENT_SIZE = 100
     private static final Integer SEGMENT_THRESHOLD = 0.75f * INITIAL_SEGMENT_SIZE
diff --git a/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy b/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy
index d87704f..357e37d 100644
--- a/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy
+++ b/src/test/org/codehaus/groovy/util/ManagedConcurrentMapTest.groovy
@@ -32,12 +32,10 @@ class ManagedConcurrentMapTest extends GroovyTestCase {
         }
 
         assert map.size() == 5
-        assert map.fullSize() == 5
 
         entries*.finalizeReference()
 
         assert map.size() == 0
-        assert map.fullSize() == 0
     }
 
 }