mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8310913: Move ReferencedKeyMap to jdk.internal so it may be shared
Reviewed-by: naoto, rriggs, mchung, liach
This commit is contained in:
parent
86783b9851
commit
6af0af5934
11 changed files with 537 additions and 275 deletions
|
@ -33,7 +33,9 @@ import java.lang.ref.ReferenceQueue;
|
|||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
@ -42,7 +44,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.util.ReferencedKeySet;
|
||||
import jdk.internal.util.ReferenceKey;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import sun.invoke.util.VerifyType;
|
||||
|
@ -227,7 +230,13 @@ class MethodType
|
|||
return new IndexOutOfBoundsException(num.toString());
|
||||
}
|
||||
|
||||
static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
|
||||
static final ReferencedKeySet<MethodType> internTable =
|
||||
ReferencedKeySet.create(false, true, new Supplier<>() {
|
||||
@Override
|
||||
public Map<ReferenceKey<MethodType>, ReferenceKey<MethodType>> get() {
|
||||
return new ConcurrentHashMap<>(512);
|
||||
}
|
||||
});
|
||||
|
||||
static final Class<?>[] NO_PTYPES = {};
|
||||
|
||||
|
@ -405,7 +414,7 @@ class MethodType
|
|||
mt = new MethodType(rtype, ptypes);
|
||||
}
|
||||
mt.form = MethodTypeForm.findForm(mt);
|
||||
return internTable.add(mt);
|
||||
return internTable.intern(mt);
|
||||
}
|
||||
private static final @Stable MethodType[] objectOnlyTypes = new MethodType[20];
|
||||
|
||||
|
@ -883,10 +892,6 @@ class MethodType
|
|||
* @param x object to compare
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
// This implementation may also return true if x is a WeakEntry containing
|
||||
// a method type that is equal to this. This is an internal implementation
|
||||
// detail to allow for faster method type lookups.
|
||||
// See ConcurrentWeakInternSet.WeakEntry#equals(Object)
|
||||
@Override
|
||||
public boolean equals(Object x) {
|
||||
if (this == x) {
|
||||
|
@ -895,10 +900,6 @@ class MethodType
|
|||
if (x instanceof MethodType mt) {
|
||||
return equals(mt);
|
||||
}
|
||||
if (x instanceof ConcurrentWeakInternSet.WeakEntry<?> e
|
||||
&& e.get() instanceof MethodType mt) {
|
||||
return equals(mt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1390,112 +1391,4 @@ s.writeObject(this.parameterArray());
|
|||
wrapAlt = null;
|
||||
return mt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of weak concurrent intern set.
|
||||
*
|
||||
* @param <T> interned type
|
||||
*/
|
||||
private static class ConcurrentWeakInternSet<T> {
|
||||
|
||||
private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
|
||||
private final ReferenceQueue<T> stale;
|
||||
|
||||
public ConcurrentWeakInternSet() {
|
||||
this.map = new ConcurrentHashMap<>(512);
|
||||
this.stale = SharedSecrets.getJavaLangRefAccess().newNativeReferenceQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the existing interned element.
|
||||
* This method returns null if no element is interned.
|
||||
*
|
||||
* @param elem element to look up
|
||||
* @return the interned element
|
||||
*/
|
||||
public T get(T elem) {
|
||||
if (elem == null) throw new NullPointerException();
|
||||
expungeStaleElements();
|
||||
|
||||
WeakEntry<T> value = map.get(elem);
|
||||
if (value != null) {
|
||||
T res = value.get();
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns the element.
|
||||
* Always returns non-null element, matching the one in the intern set.
|
||||
* Under the race against another add(), it can return <i>different</i>
|
||||
* element, if another thread beats us to interning it.
|
||||
*
|
||||
* @param elem element to add
|
||||
* @return element that was actually added
|
||||
*/
|
||||
public T add(T elem) {
|
||||
if (elem == null) throw new NullPointerException();
|
||||
|
||||
// Playing double race here, and so spinloop is required.
|
||||
// First race is with two concurrent updaters.
|
||||
// Second race is with GC purging weak ref under our feet.
|
||||
// Hopefully, we almost always end up with a single pass.
|
||||
T interned;
|
||||
WeakEntry<T> e = new WeakEntry<>(elem, stale);
|
||||
do {
|
||||
expungeStaleElements();
|
||||
WeakEntry<T> exist = map.putIfAbsent(e, e);
|
||||
interned = (exist == null) ? elem : exist.get();
|
||||
} while (interned == null);
|
||||
return interned;
|
||||
}
|
||||
|
||||
private void expungeStaleElements() {
|
||||
Reference<? extends T> reference;
|
||||
while ((reference = stale.poll()) != null) {
|
||||
map.remove(reference);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WeakEntry<T> extends WeakReference<T> {
|
||||
|
||||
public final int hashcode;
|
||||
|
||||
public WeakEntry(T key, ReferenceQueue<T> queue) {
|
||||
super(key, queue);
|
||||
hashcode = key.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns {@code true} if {@code obj} is another
|
||||
* {@code WeakEntry} whose referent is equal to this referent, or
|
||||
* if {@code obj} is equal to the referent of this. This allows
|
||||
* lookups to be made without wrapping in a {@code WeakEntry}.
|
||||
*
|
||||
* @param obj the object to compare
|
||||
* @return true if {@code obj} is equal to this or the referent of this
|
||||
* @see MethodType#equals(Object)
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
Object mine = get();
|
||||
if (obj instanceof WeakEntry<?> we) {
|
||||
Object that = we.get();
|
||||
return (that == null || mine == null) ? (this == obj) : mine.equals(that);
|
||||
}
|
||||
return (mine == null) ? (obj == null) : mine.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.Objects;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ReferencedKeyMap;
|
||||
|
||||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
|
@ -366,7 +367,7 @@ final class Carriers {
|
|||
* Cache mapping {@link MethodType} to previously defined {@link CarrierElements}.
|
||||
*/
|
||||
private static final Map<MethodType, CarrierElements>
|
||||
methodTypeCache = ReferencedKeyMap.create(ConcurrentHashMap::new);
|
||||
methodTypeCache = ReferencedKeyMap.create(false, ConcurrentHashMap::new);
|
||||
|
||||
/**
|
||||
* Permute a raw constructor and component accessor {@link MethodHandle MethodHandles} to
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* View/wrapper of keys used by the backing {@link ReferencedKeyMap}.
|
||||
* There are two style of keys; one for entries in the backing map and
|
||||
* one for queries to the backing map. This second style avoids the
|
||||
* overhead of a {@link Reference} object.
|
||||
*
|
||||
* @param <T> key type
|
||||
*
|
||||
* @since 21
|
||||
*
|
||||
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
||||
* Do not rely on its availability.
|
||||
*/
|
||||
sealed interface ReferenceKey<T> permits StrongReferenceKey, WeakReferenceKey, SoftReferenceKey {
|
||||
/**
|
||||
* {@return the value of the unwrapped key}
|
||||
*/
|
||||
T get();
|
||||
|
||||
/**
|
||||
* Cleanup unused key.
|
||||
*/
|
||||
void unused();
|
||||
|
||||
}
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This class provides management of {@link Map maps} where it is desirable to
|
||||
* remove entries automatically when the key is garbage collected. This is
|
||||
* accomplished by using a backing map where the keys are either a
|
||||
* {@link WeakReference} or a {@link SoftReference}.
|
||||
* <p>
|
||||
* To create a {@link ReferencedKeyMap} the user must provide a {@link Supplier}
|
||||
* of the backing map and whether {@link WeakReference} or
|
||||
* {@link SoftReference} is to be used.
|
||||
*
|
||||
* {@snippet :
|
||||
* // Use HashMap and WeakReference
|
||||
* Map<Long, String> map = ReferencedKeyMap.create(false, HashMap::new);
|
||||
* map.put(10_000_000L, "a");
|
||||
* map.put(10_000_001L, "b");
|
||||
* map.put(10_000_002L, "c");
|
||||
* map.put(10_000_003L, "d");
|
||||
* map.put(10_000_004L, "e");
|
||||
*
|
||||
* // Use ConcurrentHashMap and SoftReference
|
||||
* map = ReferencedKeyMap.create(true, ConcurrentHashMap::new);
|
||||
* map.put(20_000_000L, "v");
|
||||
* map.put(20_000_001L, "w");
|
||||
* map.put(20_000_002L, "x");
|
||||
* map.put(20_000_003L, "y");
|
||||
* map.put(20_000_004L, "z");
|
||||
* }
|
||||
*
|
||||
* @implNote Care must be given that the backing map does replacement by
|
||||
* replacing the value in the map entry instead of deleting the old entry and
|
||||
* adding a new entry, otherwise replaced entries may end up with a strongly
|
||||
* referenced key. {@link HashMap} and {@link ConcurrentHashMap} are known
|
||||
* to be safe.
|
||||
*
|
||||
* @param <K> the type of keys maintained by this map
|
||||
* @param <V> the type of mapped values
|
||||
*
|
||||
* @since 21
|
||||
*
|
||||
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
||||
* Do not rely on its availability.
|
||||
*/
|
||||
final class ReferencedKeyMap<K, V> implements Map<K, V> {
|
||||
/**
|
||||
* true if {@link SoftReference} keys are to be used,
|
||||
* {@link WeakReference} otherwise.
|
||||
*/
|
||||
private final boolean isSoft;
|
||||
|
||||
/**
|
||||
* Backing {@link Map}.
|
||||
*/
|
||||
private final Map<ReferenceKey<K>, V> map;
|
||||
|
||||
/**
|
||||
* {@link ReferenceQueue} for cleaning up {@link WeakReferenceKey EntryKeys}.
|
||||
*/
|
||||
private final ReferenceQueue<K> stale;
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* @param isSoft true if {@link SoftReference} keys are to
|
||||
* be used, {@link WeakReference} otherwise.
|
||||
* @param map backing map
|
||||
*/
|
||||
private ReferencedKeyMap(boolean isSoft, Map<ReferenceKey<K>, V> map) {
|
||||
this.isSoft = isSoft;
|
||||
this.map = map;
|
||||
this.stale = new ReferenceQueue<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReferencedKeyMap} map.
|
||||
*
|
||||
* @param isSoft true if {@link SoftReference} keys are to
|
||||
* be used, {@link WeakReference} otherwise.
|
||||
* @param supplier {@link Supplier} of the backing map
|
||||
*
|
||||
* @return a new map with {@link Reference} keys
|
||||
*
|
||||
* @param <K> the type of keys maintained by the new map
|
||||
* @param <V> the type of mapped values
|
||||
*/
|
||||
static <K, V> ReferencedKeyMap<K, V>
|
||||
create(boolean isSoft, Supplier<Map<ReferenceKey<K>, V>> supplier) {
|
||||
return new ReferencedKeyMap<K, V>(isSoft, supplier.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReferencedKeyMap} map using
|
||||
* {@link WeakReference} keys.
|
||||
*
|
||||
* @param supplier {@link Supplier} of the backing map
|
||||
*
|
||||
* @return a new map with {@link Reference} keys
|
||||
*
|
||||
* @param <K> the type of keys maintained by the new map
|
||||
* @param <V> the type of mapped values
|
||||
*/
|
||||
static <K, V> ReferencedKeyMap<K, V>
|
||||
create(Supplier<Map<ReferenceKey<K>, V>> supplier) {
|
||||
return new ReferencedKeyMap<K, V>(false, supplier.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a key suitable for a map entry}
|
||||
*
|
||||
* @param key unwrapped key
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private ReferenceKey<K> entryKey(Object key) {
|
||||
if (isSoft) {
|
||||
return new SoftReferenceKey<>((K)key, stale);
|
||||
} else {
|
||||
return new WeakReferenceKey<>((K)key, stale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a key suitable for lookup}
|
||||
*
|
||||
* @param key unwrapped key
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private ReferenceKey<K> lookupKey(Object key) {
|
||||
return new StrongReferenceKey<>((K)key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
removeStaleReferences();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
removeStaleReferences();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
Objects.requireNonNull(key, "key must not be null");
|
||||
removeStaleReferences();
|
||||
return map.containsKey(lookupKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
Objects.requireNonNull(value, "value must not be null");
|
||||
removeStaleReferences();
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
Objects.requireNonNull(key, "key must not be null");
|
||||
removeStaleReferences();
|
||||
return map.get(lookupKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V newValue) {
|
||||
Objects.requireNonNull(key, "key must not be null");
|
||||
Objects.requireNonNull(newValue, "value must not be null");
|
||||
removeStaleReferences();
|
||||
ReferenceKey<K> entryKey = entryKey(key);
|
||||
// If {@code put} returns non-null then was actually a {@code replace}
|
||||
// and older key was used. In that case the new key was not used and the
|
||||
// reference marked stale.
|
||||
V oldValue = map.put(entryKey, newValue);
|
||||
if (oldValue != null) {
|
||||
entryKey.unused();
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
// Rely on gc to clean up old key.
|
||||
return map.remove(lookupKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
removeStaleReferences();
|
||||
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
K key = entry.getKey();
|
||||
V value = entry.getValue();
|
||||
put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
removeStaleReferences();
|
||||
// Rely on gc to clean up old keys.
|
||||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Common routine for collecting the current set of keys.
|
||||
*
|
||||
* @return {@link Stream} of valid keys (unwrapped)
|
||||
*/
|
||||
private Stream<K> filterKeySet() {
|
||||
return map.keySet()
|
||||
.stream()
|
||||
.map(ReferenceKey::get)
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
removeStaleReferences();
|
||||
return filterKeySet().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
removeStaleReferences();
|
||||
return map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
removeStaleReferences();
|
||||
return filterKeySet()
|
||||
.map(k -> new AbstractMap.SimpleEntry<>(k, get(k)))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V newValue) {
|
||||
removeStaleReferences();
|
||||
ReferenceKey<K> entryKey = entryKey(key);
|
||||
// If {@code putIfAbsent} returns non-null then was actually a
|
||||
// {@code replace} and older key was used. In that case the new key was
|
||||
// not used and the reference marked stale.
|
||||
V oldValue = map.putIfAbsent(entryKey, newValue);
|
||||
if (oldValue != null) {
|
||||
entryKey.unused();
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
// Rely on gc to clean up old key.
|
||||
return map.remove(lookupKey(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
removeStaleReferences();
|
||||
// If replace is successful then the older key will be used and the
|
||||
// lookup key will suffice.
|
||||
return map.replace(lookupKey(key), oldValue, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V replace(K key, V value) {
|
||||
removeStaleReferences();
|
||||
// If replace is successful then the older key will be used and the
|
||||
// lookup key will suffice.
|
||||
return map.replace(lookupKey(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
removeStaleReferences();
|
||||
return filterKeySet()
|
||||
.map(k -> k + "=" + get(k))
|
||||
.collect(Collectors.joining(", ", "{", "}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes enqueued weak references from map.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeStaleReferences() {
|
||||
while (true) {
|
||||
WeakReferenceKey<K> key = (WeakReferenceKey<K>)stale.poll();
|
||||
if (key == null) {
|
||||
break;
|
||||
}
|
||||
map.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link SoftReference} wrapper key for entries in the backing map.
|
||||
*
|
||||
* @param <T> key type
|
||||
*
|
||||
* @since 21
|
||||
*
|
||||
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
||||
* Do not rely on its availability.
|
||||
*/
|
||||
final class SoftReferenceKey<T> extends SoftReference<T> implements ReferenceKey<T> {
|
||||
/**
|
||||
* Saved hashcode of the key. Used when {@link SoftReference} is
|
||||
* null.
|
||||
*/
|
||||
private final int hashcode;
|
||||
|
||||
/**
|
||||
* Package-Protected constructor.
|
||||
*
|
||||
* @param key unwrapped key value
|
||||
* @param queue reference queue
|
||||
*/
|
||||
SoftReferenceKey(T key, ReferenceQueue<T> queue) {
|
||||
super(key, queue);
|
||||
this.hashcode = Objects.hashCode(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup unused key. No need to enqueue since the key did not make it
|
||||
* into the map.
|
||||
*/
|
||||
@Override
|
||||
public void unused() {
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// Necessary when removing a null reference
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
// Necessary when comparing an unwrapped key
|
||||
if (obj instanceof ReferenceKey<?> key) {
|
||||
obj = key.get();
|
||||
}
|
||||
return Objects.equals(get(), obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Use saved hashcode
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getCanonicalName() + "#" + System.identityHashCode(this);
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for querying the backing map. Avoids the overhead of an
|
||||
* {@link java.lang.ref.Reference} object.
|
||||
*
|
||||
* @param <T> key type
|
||||
*
|
||||
* @since 21
|
||||
*
|
||||
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
||||
* Do not rely on its availability.
|
||||
*/
|
||||
final class StrongReferenceKey<T> implements ReferenceKey<T> {
|
||||
T key;
|
||||
|
||||
/**
|
||||
* Package-Protected constructor.
|
||||
*
|
||||
* @param key unwrapped key value
|
||||
*/
|
||||
StrongReferenceKey(T key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the unwrapped key}
|
||||
*/
|
||||
@Override
|
||||
public T get() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unused() {
|
||||
key = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// Necessary when comparing an unwrapped key
|
||||
if (obj instanceof ReferenceKey<?> key) {
|
||||
obj = key.get();
|
||||
}
|
||||
return Objects.equals(get(), obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Use unwrapped key hash code
|
||||
return get().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getCanonicalName() + "#" + System.identityHashCode(this);
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link WeakReference} wrapper key for entries in the backing map.
|
||||
*
|
||||
* @param <T> key type
|
||||
*
|
||||
* @since 21
|
||||
*
|
||||
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
||||
* Do not rely on its availability.
|
||||
*/
|
||||
final class WeakReferenceKey<T> extends WeakReference<T> implements ReferenceKey<T> {
|
||||
/**
|
||||
* Saved hashcode of the key. Used when {@link WeakReference} is
|
||||
* null.
|
||||
*/
|
||||
private final int hashcode;
|
||||
|
||||
/**
|
||||
* Package-Protected constructor.
|
||||
*
|
||||
* @param key unwrapped key value
|
||||
* @param queue reference queue
|
||||
*/
|
||||
WeakReferenceKey(T key, ReferenceQueue<T> queue) {
|
||||
super(key, queue);
|
||||
this.hashcode = Objects.hashCode(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup unused key. No need to enqueue since the key did not make it
|
||||
* into the map.
|
||||
*/
|
||||
@Override
|
||||
public void unused() {
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// Necessary when removing a null reference
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
// Necessary when comparing an unwrapped key
|
||||
if (obj instanceof ReferenceKey<?> key) {
|
||||
obj = key.get();
|
||||
}
|
||||
return Objects.equals(get(), obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Use saved hashcode
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getCanonicalName() + "#" + System.identityHashCode(this);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue