6519182: SunToolkit.appContextMap should be IdentityMap
Reviewed-by: ant, azvegint
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Mon Jun 22 13:28:57 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Tue Jun 23 09:54:19 2015 +0300
@@ -291,7 +291,7 @@
// Maps from non-Component/MenuComponent to AppContext.
// WeakHashMap<Component,AppContext>
private static final Map<Object, AppContext> appContextMap =
- Collections.synchronizedMap(new WeakHashMap<Object, AppContext>());
+ Collections.synchronizedMap(new WeakIdentityHashMap<Object, AppContext>());
/**
* Sets the appContext field of target. If target is not a Component or
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/awt/WeakIdentityHashMap.java Tue Jun 23 09:54:19 2015 +0300
@@ -0,0 +1,195 @@
+package sun.awt;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.*;
+
+// A weak key reference hash map that uses System.identityHashCode() and "=="
+// instead of hashCode() and equals(Object)
+class WeakIdentityHashMap<K, V> implements Map<K, V> {
+ private final Map<WeakKey<K>, V> map;
+ private final transient ReferenceQueue<K> queue = new ReferenceQueue<K>();
+
+ /**
+ * Constructs a new, empty identity hash map with a default initial
+ * size (16).
+ */
+ public WeakIdentityHashMap() {
+ map = new HashMap<>(16);
+ }
+
+ /**
+ * Constructs a new, empty identity map with the specified initial size.
+ */
+ public WeakIdentityHashMap(int initialSize) {
+ map = new HashMap<>(initialSize);
+ }
+
+ private Map<WeakKey<K>, V> getMap() {
+ for(Reference<? extends K> ref; (ref = this.queue.poll()) != null;) {
+ map.remove(ref);
+ }
+ return map;
+ }
+
+ @Override
+ public int size() {
+ return getMap().size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return getMap().isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return getMap().containsKey(new WeakKey<>(key, null));
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return getMap().containsValue(value);
+ }
+
+ @Override
+ public V get(Object key) {
+ return getMap().get(new WeakKey<>(key, null));
+ }
+
+ @Override
+ public V put(K key, V value) {
+ return getMap().put(new WeakKey<K>(key, queue), value);
+ }
+
+ @Override
+ public V remove(Object key) {
+ return getMap().remove(new WeakKey<>(key, null));
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public void clear() {
+ getMap().clear();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return new AbstractSet<K>() {
+ @Override
+ public Iterator<K> iterator() {
+ return new Iterator<K>() {
+ private K next;
+ Iterator<WeakKey<K>> iterator = getMap().keySet().iterator();
+
+ @Override
+ public boolean hasNext() {
+ while (iterator.hasNext()) {
+ if ((next = iterator.next().get()) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public K next() {
+ if(next == null && !hasNext()) {
+ throw new NoSuchElementException();
+ }
+ K ret = next;
+ next = null;
+ return ret;
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return getMap().keySet().size();
+ }
+ };
+ }
+
+ @Override
+ public Collection<V> values() {
+ return getMap().values();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return new AbstractSet<Entry<K, V>>() {
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<WeakKey<K>, V>> iterator = getMap().entrySet().iterator();
+ return new Iterator<Entry<K, V>>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ return new Entry<K, V>() {
+ Entry<WeakKey<K>, V> entry = iterator.next();
+
+ @Override
+ public K getKey() {
+ return entry.getKey().get();
+ }
+
+ @Override
+ public V getValue() {
+ return entry.getValue();
+ }
+
+ @Override
+ public V setValue(V value) {
+ return null;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return getMap().entrySet().size();
+ }
+ };
+ }
+
+ private static class WeakKey<K> extends WeakReference<K> {
+ private final int hash;
+
+ WeakKey(K key, ReferenceQueue <K> q) {
+ super(key, q);
+ hash = System.identityHashCode(key);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if(this == o) {
+ return true;
+ } else if( o instanceof WeakKey ) {
+ return get() == ((WeakKey)o).get();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+ }
+
+
+}