diff agent/src/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/LongHashMap.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc.  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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger;
+
+import java.util.*;
+
+/**
+ * This is a copy of java.util.HashMap which uses longs as keys
+ * instead of Objects. It turns out that using this in the PageCache
+ * implementation speeds up heap traversals by a factor of three.
+ *
+ * @author  Josh Bloch
+ * @author Arthur van Hoff
+ */
+
+public class LongHashMap
+{
+    static class Entry {
+        private int    hash;
+        private long   key;
+        private Object value;
+        private Entry  next;
+
+        Entry(int hash, long key, Object value, Entry next) {
+            this.hash  = hash;
+            this.key   = key;
+            this.value = value;
+            this.next  = next;
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry.
+         */
+        long getKey() { return key; }
+
+        /**
+         * Returns the value corresponding to this entry.  If the mapping
+         * has been removed from the backing map (by the iterator's
+         * <tt>remove</tt> operation), the results of this call are undefined.
+         *
+         * @return the value corresponding to this entry.
+         */
+        Object getValue() { return value; }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  (Writes through to the map.)  The
+         * behavior of this call is undefined if the mapping has already been
+         * removed from the map (by the iterator's <tt>remove</tt> operation).
+         *
+         * @param value new value to be stored in this entry.
+         * @return old value corresponding to the entry.
+         *
+         * @throws UnsupportedOperationException if the <tt>put</tt> operation
+         *            is not supported by the backing map.
+         * @throws ClassCastException if the class of the specified value
+         *            prevents it from being stored in the backing map.
+         * @throws    IllegalArgumentException if some aspect of this value
+         *            prevents it from being stored in the backing map.
+         * @throws NullPointerException the backing map does not permit
+         *            <tt>null</tt> values, and the specified value is
+         *            <tt>null</tt>.
+         */
+        Object setValue(Object value) {
+            Object oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns <tt>true</tt> if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
+         * if<pre>
+         *     (e1.getKey()==null ?
+         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &&
+         *     (e1.getValue()==null ?
+         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
+         * </pre>
+         * This ensures that the <tt>equals</tt> method works properly across
+         * different implementations of the <tt>Map.Entry</tt> interface.
+         *
+         * @param o object to be compared for equality with this map entry.
+         * @return <tt>true</tt> if the specified object is equal to this map
+         *         entry.
+         */
+        public boolean equals(Object o) {
+            if (!(o instanceof Entry))
+                return false;
+            Entry e = (Entry)o;
+            return (key == e.getKey()) && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry <tt>e</tt> is defined to be: <pre>
+         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
+         * </pre>
+         * This ensures that <tt>e1.equals(e2)</tt> implies that
+         * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
+         * <tt>e1</tt> and <tt>e2</tt>, as required by the general
+         * contract of <tt>Object.hashCode</tt>.
+         *
+         * @return the hash code value for this map entry.
+         * @see Object#hashCode()
+         * @see Object#equals(Object)
+         * @see #equals(Object)
+         */
+        public int hashCode() {
+            return hash ^ (value==null ? 0 : value.hashCode());
+        }
+    }
+
+    /**
+     * The hash table data.
+     */
+    transient Entry table[];
+
+    /**
+     * The total number of mappings in the hash table.
+     */
+    transient int size;
+
+    /**
+     * The table is rehashed when its size exceeds this threshold.  (The
+     * value of this field is (int)(capacity * loadFactor).)
+     *
+     * @serial
+     */
+    int threshold;
+
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient int modCount = 0;
+
+    /**
+     * Constructs a new, empty map with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the HashMap.
+     * @param      loadFactor        the load factor of the HashMap
+     * @throws     IllegalArgumentException  if the initial capacity is less
+     *               than zero, or if the load factor is nonpositive.
+     */
+    public LongHashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Initial Capacity: "+
+                                               initialCapacity);
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load factor: "+
+                                               loadFactor);
+        if (initialCapacity==0)
+            initialCapacity = 1;
+        this.loadFactor = loadFactor;
+        table = new Entry[initialCapacity];
+        threshold = (int)(initialCapacity * loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty map with the specified initial capacity
+     * and default load factor, which is <tt>0.75</tt>.
+     *
+     * @param   initialCapacity   the initial capacity of the HashMap.
+     * @throws    IllegalArgumentException if the initial capacity is less
+     *              than zero.
+     */
+    public LongHashMap(int initialCapacity) {
+        this(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Constructs a new, empty map with a default capacity and load
+     * factor, which is <tt>0.75</tt>.
+     */
+    public LongHashMap() {
+        this(11, 0.75f);
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map.
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     *
+     * @return <tt>true</tt> if this map contains no key-value mappings.
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns the value to which this map maps the specified key.  Returns
+     * <tt>null</tt> if the map contains no mapping for this key.  A return
+     * value of <tt>null</tt> does not <i>necessarily</i> indicate that the
+     * map contains no mapping for the key; it's also possible that the map
+     * explicitly maps the key to <tt>null</tt>.  The <tt>containsKey</tt>
+     * operation may be used to distinguish these two cases.
+     *
+     * @return the value to which this map maps the specified key.
+     * @param key key whose associated value is to be returned.
+     */
+    public Object get(long key) {
+        Entry e = getEntry(key);
+        return (e == null ? null : e.value);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     *
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     * @param key key whose presence in this Map is to be tested.
+     */
+    public boolean containsKey(long key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in the
+     * HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    Entry getEntry(long key) {
+        Entry tab[] = table;
+        int hash = (int) key;
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+
+        for (Entry e = tab[index]; e != null; e = e.next)
+            if (e.hash == hash && e.key ==key)
+                return e;
+
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested.
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value.
+     */
+    public boolean containsValue(Object value) {
+        Entry tab[] = table;
+
+        if (value==null) {
+            for (int i = tab.length ; i-- > 0 ;)
+                for (Entry e = tab[i] ; e != null ; e = e.next)
+                    if (e.value==null)
+                        return true;
+        } else {
+            for (int i = tab.length ; i-- > 0 ;)
+                for (Entry e = tab[i] ; e != null ; e = e.next)
+                    if (value.equals(e.value))
+                        return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *         if there was no mapping for key.  A <tt>null</tt> return can
+     *         also indicate that the HashMap previously associated
+     *         <tt>null</tt> with the specified key.
+     */
+    public Object put(long key, Object value) {
+        Entry tab[] = table;
+        int hash = (int) key;
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+
+        // Look for entry in hash table
+        for (Entry e = tab[index] ; e != null ; e = e.next) {
+            if (e.hash == hash && e.key == key) {
+                Object oldValue = e.value;
+                e.value = value;
+                return oldValue;
+            }
+        }
+
+        // It's not there; grow the hash table if necessary...
+        modCount++;
+        if (size >= threshold) {
+            rehash();
+            tab = table;
+            index = (hash & 0x7FFFFFFF) % tab.length;
+        }
+
+        // ...and add the entry
+        size++;
+        tab[index] = newEntry(hash, key, value, tab[index]);
+        return null;
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key key whose mapping is to be removed from the map.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *         if there was no mapping for key.  A <tt>null</tt> return can
+     *         also indicate that the map previously associated <tt>null</tt>
+     *         with the specified key.
+     */
+    public Object remove(long key) {
+        Entry e = removeEntryForKey(key);
+        return (e == null ? null : e.value);
+    }
+
+    /**
+     * Removes and returns the entry associated with the specified key
+     * in the HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    Entry removeEntryForKey(long key) {
+        Entry tab[] = table;
+        int hash = (int) key;
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+
+        for (Entry e = tab[index], prev = null; e != null;
+             prev = e, e = e.next) {
+            if (e.hash == hash && e.key == key) {
+                modCount++;
+                if (prev != null)
+                    prev.next = e.next;
+                else
+                    tab[index] = e.next;
+
+                size--;
+                return e;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Removes the specified entry from this HashMap (and increments modCount).
+     *
+     * @throws ConcurrentModificationException if the entry is not in the Map
+     */
+    void removeEntry(Entry doomed) {
+        Entry[] tab = table;
+        int index = (doomed.hash & 0x7FFFFFFF) % tab.length;
+
+        for (Entry e = tab[index], prev = null; e != null;
+             prev = e, e = e.next) {
+            if (e == doomed) {
+                modCount++;
+                if (prev == null)
+                    tab[index] = e.next;
+                else
+                    prev.next = e.next;
+                size--;
+                return;
+            }
+        }
+        throw new ConcurrentModificationException();
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        Entry tab[] = table;
+        modCount++;
+        for (int index = tab.length; --index >= 0; )
+            tab[index] = null;
+        size = 0;
+    }
+
+    /**
+     * Rehashes the contents of this map into a new <tt>HashMap</tt> instance
+     * with a larger capacity. This method is called automatically when the
+     * number of keys in this map exceeds its capacity and load factor.
+     */
+    void rehash() {
+        Entry oldTable[] = table;
+        int oldCapacity = oldTable.length;
+        int newCapacity = oldCapacity * 2 + 1;
+        Entry newTable[] = new Entry[newCapacity];
+
+        modCount++;
+        threshold = (int)(newCapacity * loadFactor);
+        table = newTable;
+
+        for (int i = oldCapacity ; i-- > 0 ;) {
+            for (Entry old = oldTable[i] ; old != null ; ) {
+                Entry e = old;
+                old = old.next;
+
+                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+                e.next = newTable[index];
+                newTable[index] = e;
+            }
+        }
+    }
+
+    static boolean eq(Object o1, Object o2) {
+        return (o1==null ? o2==null : o1.equals(o2));
+    }
+
+    Entry newEntry(int hash, long key, Object value, Entry next) {
+        return new Entry(hash, key, value, next);
+    }
+
+    int capacity() {
+        return table.length;
+    }
+
+    float loadFactor() {
+        return loadFactor;
+    }
+}