6519182: SunToolkit.appContextMap should be IdentityMap
authorssadetsky
Tue, 23 Jun 2015 09:54:19 +0300
changeset 31447 a5d56b872e3a
parent 31446 b4b7fd7c100d
child 31448 1066345d2a8a
6519182: SunToolkit.appContextMap should be IdentityMap Reviewed-by: ant, azvegint
jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java
jdk/src/java.desktop/share/classes/sun/awt/WeakIdentityHashMap.java
--- 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;
+        }
+    }
+
+
+}