changeset 1860:0355c370f1d1

Merge
author asaha
date Fri, 06 Nov 2009 16:07:52 -0800
parents d4dc3a2acdaa 285f9f567cb4
children faef4883062b
files
diffstat 5 files changed, 951 insertions(+), 295 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/Formatter.java	Fri Nov 06 19:48:09 2009 +0300
+++ b/src/share/classes/java/util/Formatter.java	Fri Nov 06 16:07:52 2009 -0800
@@ -2485,55 +2485,45 @@
 
     private static Pattern fsPattern = Pattern.compile(formatSpecifier);
 
-    // Look for format specifiers in the format string.
+    /**
+     * Finds format specifiers in the format string.
+     */
     private FormatString[] parse(String s) {
-        ArrayList al = new ArrayList();
+        ArrayList<FormatString> al = new ArrayList<FormatString>();
         Matcher m = fsPattern.matcher(s);
-        int i = 0;
-        while (i < s.length()) {
+        for (int i = 0, len = s.length(); i < len; ) {
             if (m.find(i)) {
                 // Anything between the start of the string and the beginning
                 // of the format specifier is either fixed text or contains
                 // an invalid format string.
                 if (m.start() != i) {
                     // Make sure we didn't miss any invalid format specifiers
-                    checkText(s.substring(i, m.start()));
+                    checkText(s, i, m.start());
                     // Assume previous characters were fixed text
                     al.add(new FixedString(s.substring(i, m.start())));
                 }
 
-                // Expect 6 groups in regular expression
-                String[] sa = new String[6];
-                for (int j = 0; j < m.groupCount(); j++)
-                    {
-                    sa[j] = m.group(j + 1);
-//                  System.out.print(sa[j] + " ");
-                    }
-//              System.out.println();
-                al.add(new FormatSpecifier(this, sa));
+                al.add(new FormatSpecifier(m));
                 i = m.end();
             } else {
                 // No more valid format specifiers.  Check for possible invalid
                 // format specifiers.
-                checkText(s.substring(i));
+                checkText(s, i, len);
                 // The rest of the string is fixed text
                 al.add(new FixedString(s.substring(i)));
                 break;
             }
         }
-//      FormatString[] fs = new FormatString[al.size()];
-//      for (int j = 0; j < al.size(); j++)
-//          System.out.println(((FormatString) al.get(j)).toString());
-        return (FormatString[]) al.toArray(new FormatString[0]);
+        return al.toArray(new FormatString[al.size()]);
     }
 
-    private void checkText(String s) {
-        int idx;
-        // If there are any '%' in the given string, we got a bad format
-        // specifier.
-        if ((idx = s.indexOf('%')) != -1) {
-            char c = (idx > s.length() - 2 ? '%' : s.charAt(idx + 1));
-            throw new UnknownFormatConversionException(String.valueOf(c));
+    private static void checkText(String s, int start, int end) {
+        for (int i = start; i < end; i++) {
+            // Any '%' found in the region starts an invalid format specifier.
+            if (s.charAt(i) == '%') {
+                char c = (i == end - 1) ? '%' : s.charAt(i + 1);
+                throw new UnknownFormatConversionException(String.valueOf(c));
+            }
         }
     }
 
@@ -2562,8 +2552,6 @@
         private boolean dt = false;
         private char c;
 
-        private Formatter formatter;
-
         // cache the line separator
         private String ls;
 
@@ -2650,21 +2638,22 @@
             return c;
         }
 
-        FormatSpecifier(Formatter formatter, String[] sa) {
-            this.formatter = formatter;
-            int idx = 0;
-
-            index(sa[idx++]);
-            flags(sa[idx++]);
-            width(sa[idx++]);
-            precision(sa[idx++]);
-
-            if (sa[idx] != null) {
+        FormatSpecifier(Matcher m) {
+            int idx = 1;
+
+            index(m.group(idx++));
+            flags(m.group(idx++));
+            width(m.group(idx++));
+            precision(m.group(idx++));
+
+            String tT = m.group(idx++);
+            if (tT != null) {
                 dt = true;
-                if (sa[idx].equals("T"))
+                if (tT.equals("T"))
                     f.add(Flags.UPPERCASE);
             }
-            conversion(sa[++idx]);
+
+            conversion(m.group(idx));
 
             if (dt)
                 checkDateTime();
@@ -2819,9 +2808,9 @@
 
         private void printString(Object arg, Locale l) throws IOException {
             if (arg instanceof Formattable) {
-                Formatter fmt = formatter;
-                if (formatter.locale() != l)
-                    fmt = new Formatter(formatter.out(), l);
+                Formatter fmt = Formatter.this;
+                if (fmt.locale() != l)
+                    fmt = new Formatter(fmt.out(), l);
                 ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
             } else {
                 if (f.contains(Flags.ALTERNATE))
--- a/src/share/classes/java/util/LinkedList.java	Fri Nov 06 19:48:09 2009 +0300
+++ b/src/share/classes/java/util/LinkedList.java	Fri Nov 06 16:07:52 2009 -0800
@@ -26,22 +26,22 @@
 package java.util;
 
 /**
- * Linked list implementation of the <tt>List</tt> interface.  Implements all
+ * Linked list implementation of the {@code List} interface.  Implements all
  * optional list operations, and permits all elements (including
- * <tt>null</tt>).  In addition to implementing the <tt>List</tt> interface,
- * the <tt>LinkedList</tt> class provides uniformly named methods to
- * <tt>get</tt>, <tt>remove</tt> and <tt>insert</tt> an element at the
+ * {@code null}).  In addition to implementing the {@code List} interface,
+ * the {@code LinkedList} class provides uniformly named methods to
+ * {@code get}, {@code remove} and {@code insert} an element at the
  * beginning and end of the list.  These operations allow linked lists to be
  * used as a stack, {@linkplain Queue queue}, or {@linkplain Deque
- * double-ended queue}. <p>
+ * double-ended queue}.
  *
- * The class implements the <tt>Deque</tt> interface, providing
- * first-in-first-out queue operations for <tt>add</tt>,
- * <tt>poll</tt>, along with other stack and deque operations.<p>
+ * <p>The class implements the {@code Deque} interface, providing
+ * first-in-first-out queue operations for {@code add},
+ * {@code poll}, along with other stack and deque operations.
  *
- * All of the operations perform as could be expected for a doubly-linked
+ * <p>All of the operations perform as could be expected for a doubly-linked
  * list.  Operations that index into the list will traverse the list from
- * the beginning or the end, whichever is closer to the specified index.<p>
+ * the beginning or the end, whichever is closer to the specified index.
  *
  * <p><strong>Note that this implementation is not synchronized.</strong>
  * If multiple threads access a linked list concurrently, and at least
@@ -58,11 +58,11 @@
  * unsynchronized access to the list:<pre>
  *   List list = Collections.synchronizedList(new LinkedList(...));</pre>
  *
- * <p>The iterators returned by this class's <tt>iterator</tt> and
- * <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is
+ * <p>The iterators returned by this class's {@code iterator} and
+ * {@code listIterator} methods are <i>fail-fast</i>: if the list is
  * structurally modified at any time after the iterator is created, in
- * any way except through the Iterator's own <tt>remove</tt> or
- * <tt>add</tt> methods, the iterator will throw a {@link
+ * any way except through the Iterator's own {@code remove} or
+ * {@code add} methods, the iterator will throw a {@link
  * ConcurrentModificationException}.  Thus, in the face of concurrent
  * modification, the iterator fails quickly and cleanly, rather than
  * risking arbitrary, non-deterministic behavior at an undetermined
@@ -71,7 +71,7 @@
  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
  * as it is, generally speaking, impossible to make any hard guarantees in the
  * presence of unsynchronized concurrent modification.  Fail-fast iterators
- * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
  * Therefore, it would be wrong to write a program that depended on this
  * exception for its correctness:   <i>the fail-fast behavior of iterators
  * should be used only to detect bugs.</i>
@@ -83,7 +83,6 @@
  * @author  Josh Bloch
  * @see     List
  * @see     ArrayList
- * @see     Vector
  * @since 1.2
  * @param <E> the type of elements held in this collection
  */
@@ -92,14 +91,26 @@
     extends AbstractSequentialList<E>
     implements List<E>, Deque<E>, Cloneable, java.io.Serializable
 {
-    private transient Entry<E> header = new Entry<E>(null, null, null);
-    private transient int size = 0;
+    transient int size = 0;
+
+    /**
+     * Pointer to first node.
+     * Invariant: (first == null && last == null) ||
+     *            (first.prev == null && first.item != null)
+     */
+    transient Node<E> first;
+
+    /**
+     * Pointer to last node.
+     * Invariant: (first == null && last == null) ||
+     *            (last.next == null && last.item != null)
+     */
+    transient Node<E> last;
 
     /**
      * Constructs an empty list.
      */
     public LinkedList() {
-        header.next = header.previous = header;
     }
 
     /**
@@ -116,16 +127,129 @@
     }
 
     /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> f = first;
+        final Node<E> newNode = new Node<E>(null, e, f);
+        first = newNode;
+        if (f == null)
+            last = newNode;
+        else
+            f.prev = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Links e as last element.
+     */
+    void linkLast(E e) {
+        final Node<E> l = last;
+        final Node<E> newNode = new Node<E>(l, e, null);
+        last = newNode;
+        if (l == null)
+            first = newNode;
+        else
+            l.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Inserts element e before non-null Node succ.
+     */
+    void linkBefore(E e, Node<E> succ) {
+        // assert succ != null;
+        final Node<E> pred = succ.prev;
+        final Node<E> newNode = new Node<E>(pred, e, succ);
+        succ.prev = newNode;
+        if (pred == null)
+            first = newNode;
+        else
+            pred.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Unlinks non-null first node f.
+     */
+    private E unlinkFirst(Node<E> f) {
+        // assert f == first && f != null;
+        final E element = f.item;
+        final Node<E> next = f.next;
+        f.item = null;
+        f.next = null; // help GC
+        first = next;
+        if (next == null)
+            last = null;
+        else
+            next.prev = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null last node l.
+     */
+    private E unlinkLast(Node<E> l) {
+        // assert l == last && l != null;
+        final E element = l.item;
+        final Node<E> prev = l.prev;
+        l.item = null;
+        l.prev = null; // help GC
+        last = prev;
+        if (prev == null)
+            first = null;
+        else
+            prev.next = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null node x.
+     */
+    E unlink(Node<E> x) {
+        // assert x != null;
+        final E element = x.item;
+        final Node<E> next = x.next;
+        final Node<E> prev = x.prev;
+
+        if (prev == null) {
+            first = next;
+        } else {
+            prev.next = next;
+            x.prev = null;
+        }
+
+        if (next == null) {
+            last = prev;
+        } else {
+            next.prev = prev;
+            x.next = null;
+        }
+
+        x.item = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
      * Returns the first element in this list.
      *
      * @return the first element in this list
      * @throws NoSuchElementException if this list is empty
      */
     public E getFirst() {
-        if (size==0)
+        final Node<E> f = first;
+        if (f == null)
             throw new NoSuchElementException();
-
-        return header.next.element;
+        return f.item;
     }
 
     /**
@@ -135,10 +259,10 @@
      * @throws NoSuchElementException if this list is empty
      */
     public E getLast()  {
-        if (size==0)
+        final Node<E> l = last;
+        if (l == null)
             throw new NoSuchElementException();
-
-        return header.previous.element;
+        return l.item;
     }
 
     /**
@@ -148,7 +272,10 @@
      * @throws NoSuchElementException if this list is empty
      */
     public E removeFirst() {
-        return remove(header.next);
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return unlinkFirst(f);
     }
 
     /**
@@ -158,7 +285,10 @@
      * @throws NoSuchElementException if this list is empty
      */
     public E removeLast() {
-        return remove(header.previous);
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return unlinkLast(l);
     }
 
     /**
@@ -167,7 +297,7 @@
      * @param e the element to add
      */
     public void addFirst(E e) {
-        addBefore(e, header.next);
+        linkFirst(e);
     }
 
     /**
@@ -178,17 +308,17 @@
      * @param e the element to add
      */
     public void addLast(E e) {
-        addBefore(e, header);
+        linkLast(e);
     }
 
     /**
-     * Returns <tt>true</tt> if this list contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this list contains
-     * at least one element <tt>e</tt> such that
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
      * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
      *
      * @param o element whose presence in this list is to be tested
-     * @return <tt>true</tt> if this list contains the specified element
+     * @return {@code true} if this list contains the specified element
      */
     public boolean contains(Object o) {
         return indexOf(o) != -1;
@@ -209,10 +339,10 @@
      * <p>This method is equivalent to {@link #addLast}.
      *
      * @param e element to be appended to this list
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
+     * @return {@code true} (as specified by {@link Collection#add})
      */
     public boolean add(E e) {
-        addBefore(e, header);
+        linkLast(e);
         return true;
     }
 
@@ -220,27 +350,27 @@
      * Removes the first occurrence of the specified element from this list,
      * if it is present.  If this list does not contain the element, it is
      * unchanged.  More formally, removes the element with the lowest index
-     * <tt>i</tt> such that
+     * {@code i} such that
      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
-     * (if such an element exists).  Returns <tt>true</tt> if this list
+     * (if such an element exists).  Returns {@code true} if this list
      * contained the specified element (or equivalently, if this list
      * changed as a result of the call).
      *
      * @param o element to be removed from this list, if present
-     * @return <tt>true</tt> if this list contained the specified element
+     * @return {@code true} if this list contained the specified element
      */
     public boolean remove(Object o) {
-        if (o==null) {
-            for (Entry<E> e = header.next; e != header; e = e.next) {
-                if (e.element==null) {
-                    remove(e);
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null) {
+                    unlink(x);
                     return true;
                 }
             }
         } else {
-            for (Entry<E> e = header.next; e != header; e = e.next) {
-                if (o.equals(e.element)) {
-                    remove(e);
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item)) {
+                    unlink(x);
                     return true;
                 }
             }
@@ -257,7 +387,7 @@
      * this list, and it's nonempty.)
      *
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
+     * @return {@code true} if this list changed as a result of the call
      * @throws NullPointerException if the specified collection is null
      */
     public boolean addAll(Collection<? extends E> c) {
@@ -275,45 +405,66 @@
      * @param index index at which to insert the first element
      *              from the specified collection
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
+     * @return {@code true} if this list changed as a result of the call
      * @throws IndexOutOfBoundsException {@inheritDoc}
      * @throws NullPointerException if the specified collection is null
      */
     public boolean addAll(int index, Collection<? extends E> c) {
-        if (index < 0 || index > size)
-            throw new IndexOutOfBoundsException("Index: "+index+
-                                                ", Size: "+size);
+        checkPositionIndex(index);
+
         Object[] a = c.toArray();
         int numNew = a.length;
-        if (numNew==0)
+        if (numNew == 0)
             return false;
-        modCount++;
 
-        Entry<E> successor = (index==size ? header : entry(index));
-        Entry<E> predecessor = successor.previous;
-        for (int i=0; i<numNew; i++) {
-            Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
-            predecessor.next = e;
-            predecessor = e;
+        Node<E> pred, succ;
+        if (index == size) {
+            succ = null;
+            pred = last;
+        } else {
+            succ = node(index);
+            pred = succ.prev;
         }
-        successor.previous = predecessor;
+
+        for (Object o : a) {
+            @SuppressWarnings("unchecked") E e = (E) o;
+            Node<E> newNode = new Node<E>(pred, e, null);
+            if (pred == null)
+                first = newNode;
+            else
+                pred.next = newNode;
+            pred = newNode;
+        }
+
+        if (succ == null) {
+            last = pred;
+        } else {
+            pred.next = succ;
+            succ.prev = pred;
+        }
 
         size += numNew;
+        modCount++;
         return true;
     }
 
     /**
      * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
      */
     public void clear() {
-        Entry<E> e = header.next;
-        while (e != header) {
-            Entry<E> next = e.next;
-            e.next = e.previous = null;
-            e.element = null;
-            e = next;
+        // Clearing all of the links between nodes is "unnecessary", but:
+        // - helps a generational GC if the discarded nodes inhabit
+        //   more than one generation
+        // - is sure to free memory even if there is a reachable Iterator
+        for (Node<E> x = first; x != null; ) {
+            Node<E> next = x.next;
+            x.item = null;
+            x.next = null;
+            x.prev = null;
+            x = next;
         }
-        header.next = header.previous = header;
+        first = last = null;
         size = 0;
         modCount++;
     }
@@ -329,7 +480,8 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E get(int index) {
-        return entry(index).element;
+        checkElementIndex(index);
+        return node(index).item;
     }
 
     /**
@@ -342,9 +494,10 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E set(int index, E element) {
-        Entry<E> e = entry(index);
-        E oldVal = e.element;
-        e.element = element;
+        checkElementIndex(index);
+        Node<E> x = node(index);
+        E oldVal = x.item;
+        x.item = element;
         return oldVal;
     }
 
@@ -358,7 +511,12 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public void add(int index, E element) {
-        addBefore(element, (index==size ? header : entry(index)));
+        checkPositionIndex(index);
+
+        if (index == size)
+            linkLast(element);
+        else
+            linkBefore(element, node(index));
     }
 
     /**
@@ -371,34 +529,69 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E remove(int index) {
-        return remove(entry(index));
+        checkElementIndex(index);
+        return unlink(node(index));
     }
 
     /**
-     * Returns the indexed entry.
+     * Tells if the argument is the index of an existing element.
      */
-    private Entry<E> entry(int index) {
-        if (index < 0 || index >= size)
-            throw new IndexOutOfBoundsException("Index: "+index+
-                                                ", Size: "+size);
-        Entry<E> e = header;
-        if (index < (size >> 1)) {
-            for (int i = 0; i <= index; i++)
-                e = e.next;
-        } else {
-            for (int i = size; i > index; i--)
-                e = e.previous;
-        }
-        return e;
+    private boolean isElementIndex(int index) {
+        return index >= 0 && index < size;
     }
 
+    /**
+     * Tells if the argument is the index of a valid position for an
+     * iterator or an add operation.
+     */
+    private boolean isPositionIndex(int index) {
+        return index >= 0 && index <= size;
+    }
+
+    /**
+     * Constructs an IndexOutOfBoundsException detail message.
+     * Of the many possible refactorings of the error handling code,
+     * this "outlining" performs best with both server and client VMs.
+     */
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size;
+    }
+
+    private void checkElementIndex(int index) {
+        if (!isElementIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private void checkPositionIndex(int index) {
+        if (!isPositionIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    /**
+     * Returns the (non-null) Node at the specified element index.
+     */
+    Node<E> node(int index) {
+        // assert isElementIndex(index);
+
+        if (index < (size >> 1)) {
+            Node<E> x = first;
+            for (int i = 0; i < index; i++)
+                x = x.next;
+            return x;
+        } else {
+            Node<E> x = last;
+            for (int i = size - 1; i > index; i--)
+                x = x.prev;
+            return x;
+        }
+    }
 
     // Search Operations
 
     /**
      * Returns the index of the first occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the lowest index <tt>i</tt> such that
+     * More formally, returns the lowest index {@code i} such that
      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
      * or -1 if there is no such index.
      *
@@ -408,15 +601,15 @@
      */
     public int indexOf(Object o) {
         int index = 0;
-        if (o==null) {
-            for (Entry e = header.next; e != header; e = e.next) {
-                if (e.element==null)
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null)
                     return index;
                 index++;
             }
         } else {
-            for (Entry e = header.next; e != header; e = e.next) {
-                if (o.equals(e.element))
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item))
                     return index;
                 index++;
             }
@@ -427,7 +620,7 @@
     /**
      * Returns the index of the last occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the highest index <tt>i</tt> such that
+     * More formally, returns the highest index {@code i} such that
      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
      * or -1 if there is no such index.
      *
@@ -437,16 +630,16 @@
      */
     public int lastIndexOf(Object o) {
         int index = size;
-        if (o==null) {
-            for (Entry e = header.previous; e != header; e = e.previous) {
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
                 index--;
-                if (e.element==null)
+                if (x.item == null)
                     return index;
             }
         } else {
-            for (Entry e = header.previous; e != header; e = e.previous) {
+            for (Node<E> x = last; x != null; x = x.prev) {
                 index--;
-                if (o.equals(e.element))
+                if (o.equals(x.item))
                     return index;
             }
         }
@@ -457,17 +650,18 @@
 
     /**
      * Retrieves, but does not remove, the head (first element) of this list.
-     * @return the head of this list, or <tt>null</tt> if this list is empty
+     *
+     * @return the head of this list, or {@code null} if this list is empty
      * @since 1.5
      */
     public E peek() {
-        if (size==0)
-            return null;
-        return getFirst();
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
     }
 
     /**
      * Retrieves, but does not remove, the head (first element) of this list.
+     *
      * @return the head of this list
      * @throws NoSuchElementException if this list is empty
      * @since 1.5
@@ -477,14 +671,14 @@
     }
 
     /**
-     * Retrieves and removes the head (first element) of this list
-     * @return the head of this list, or <tt>null</tt> if this list is empty
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list, or {@code null} if this list is empty
      * @since 1.5
      */
     public E poll() {
-        if (size==0)
-            return null;
-        return removeFirst();
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
     }
 
     /**
@@ -502,7 +696,7 @@
      * Adds the specified element as the tail (last element) of this list.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Queue#offer})
+     * @return {@code true} (as specified by {@link Queue#offer})
      * @since 1.5
      */
     public boolean offer(E e) {
@@ -514,7 +708,7 @@
      * Inserts the specified element at the front of this list.
      *
      * @param e the element to insert
-     * @return <tt>true</tt> (as specified by {@link Deque#offerFirst})
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
      * @since 1.6
      */
     public boolean offerFirst(E e) {
@@ -526,7 +720,7 @@
      * Inserts the specified element at the end of this list.
      *
      * @param e the element to insert
-     * @return <tt>true</tt> (as specified by {@link Deque#offerLast})
+     * @return {@code true} (as specified by {@link Deque#offerLast})
      * @since 1.6
      */
     public boolean offerLast(E e) {
@@ -536,58 +730,54 @@
 
     /**
      * Retrieves, but does not remove, the first element of this list,
-     * or returns <tt>null</tt> if this list is empty.
+     * or returns {@code null} if this list is empty.
      *
-     * @return the first element of this list, or <tt>null</tt>
+     * @return the first element of this list, or {@code null}
      *         if this list is empty
      * @since 1.6
      */
     public E peekFirst() {
-        if (size==0)
-            return null;
-        return getFirst();
-    }
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+     }
 
     /**
      * Retrieves, but does not remove, the last element of this list,
-     * or returns <tt>null</tt> if this list is empty.
+     * or returns {@code null} if this list is empty.
      *
-     * @return the last element of this list, or <tt>null</tt>
+     * @return the last element of this list, or {@code null}
      *         if this list is empty
      * @since 1.6
      */
     public E peekLast() {
-        if (size==0)
-            return null;
-        return getLast();
+        final Node<E> l = last;
+        return (l == null) ? null : l.item;
     }
 
     /**
      * Retrieves and removes the first element of this list,
-     * or returns <tt>null</tt> if this list is empty.
+     * or returns {@code null} if this list is empty.
      *
-     * @return the first element of this list, or <tt>null</tt> if
+     * @return the first element of this list, or {@code null} if
      *     this list is empty
      * @since 1.6
      */
     public E pollFirst() {
-        if (size==0)
-            return null;
-        return removeFirst();
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
     }
 
     /**
      * Retrieves and removes the last element of this list,
-     * or returns <tt>null</tt> if this list is empty.
+     * or returns {@code null} if this list is empty.
      *
-     * @return the last element of this list, or <tt>null</tt> if
+     * @return the last element of this list, or {@code null} if
      *     this list is empty
      * @since 1.6
      */
     public E pollLast() {
-        if (size==0)
-            return null;
-        return removeLast();
+        final Node<E> l = last;
+        return (l == null) ? null : unlinkLast(l);
     }
 
     /**
@@ -624,7 +814,7 @@
      * does not contain the element, it is unchanged.
      *
      * @param o element to be removed from this list, if present
-     * @return <tt>true</tt> if the list contained the specified element
+     * @return {@code true} if the list contained the specified element
      * @since 1.6
      */
     public boolean removeFirstOccurrence(Object o) {
@@ -637,21 +827,21 @@
      * does not contain the element, it is unchanged.
      *
      * @param o element to be removed from this list, if present
-     * @return <tt>true</tt> if the list contained the specified element
+     * @return {@code true} if the list contained the specified element
      * @since 1.6
      */
     public boolean removeLastOccurrence(Object o) {
-        if (o==null) {
-            for (Entry<E> e = header.previous; e != header; e = e.previous) {
-                if (e.element==null) {
-                    remove(e);
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (x.item == null) {
+                    unlink(x);
                     return true;
                 }
             }
         } else {
-            for (Entry<E> e = header.previous; e != header; e = e.previous) {
-                if (o.equals(e.element)) {
-                    remove(e);
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (o.equals(x.item)) {
+                    unlink(x);
                     return true;
                 }
             }
@@ -662,76 +852,68 @@
     /**
      * Returns a list-iterator of the elements in this list (in proper
      * sequence), starting at the specified position in the list.
-     * Obeys the general contract of <tt>List.listIterator(int)</tt>.<p>
+     * Obeys the general contract of {@code List.listIterator(int)}.<p>
      *
      * The list-iterator is <i>fail-fast</i>: if the list is structurally
      * modified at any time after the Iterator is created, in any way except
-     * through the list-iterator's own <tt>remove</tt> or <tt>add</tt>
+     * through the list-iterator's own {@code remove} or {@code add}
      * methods, the list-iterator will throw a
-     * <tt>ConcurrentModificationException</tt>.  Thus, in the face of
+     * {@code ConcurrentModificationException}.  Thus, in the face of
      * concurrent modification, the iterator fails quickly and cleanly, rather
      * than risking arbitrary, non-deterministic behavior at an undetermined
      * time in the future.
      *
      * @param index index of the first element to be returned from the
-     *              list-iterator (by a call to <tt>next</tt>)
+     *              list-iterator (by a call to {@code next})
      * @return a ListIterator of the elements in this list (in proper
      *         sequence), starting at the specified position in the list
      * @throws IndexOutOfBoundsException {@inheritDoc}
      * @see List#listIterator(int)
      */
     public ListIterator<E> listIterator(int index) {
+        checkPositionIndex(index);
         return new ListItr(index);
     }
 
     private class ListItr implements ListIterator<E> {
-        private Entry<E> lastReturned = header;
-        private Entry<E> next;
+        private Node<E> lastReturned = null;
+        private Node<E> next;
         private int nextIndex;
         private int expectedModCount = modCount;
 
         ListItr(int index) {
-            if (index < 0 || index > size)
-                throw new IndexOutOfBoundsException("Index: "+index+
-                                                    ", Size: "+size);
-            if (index < (size >> 1)) {
-                next = header.next;
-                for (nextIndex=0; nextIndex<index; nextIndex++)
-                    next = next.next;
-            } else {
-                next = header;
-                for (nextIndex=size; nextIndex>index; nextIndex--)
-                    next = next.previous;
-            }
+            // assert isPositionIndex(index);
+            next = (index == size) ? null : node(index);
+            nextIndex = index;
         }
 
         public boolean hasNext() {
-            return nextIndex != size;
+            return nextIndex < size;
         }
 
         public E next() {
             checkForComodification();
-            if (nextIndex == size)
+            if (!hasNext())
                 throw new NoSuchElementException();
 
             lastReturned = next;
             next = next.next;
             nextIndex++;
-            return lastReturned.element;
+            return lastReturned.item;
         }
 
         public boolean hasPrevious() {
-            return nextIndex != 0;
+            return nextIndex > 0;
         }
 
         public E previous() {
-            if (nextIndex == 0)
+            checkForComodification();
+            if (!hasPrevious())
                 throw new NoSuchElementException();
 
-            lastReturned = next = next.previous;
+            lastReturned = next = (next == null) ? last : next.prev;
             nextIndex--;
-            checkForComodification();
-            return lastReturned.element;
+            return lastReturned.item;
         }
 
         public int nextIndex() {
@@ -739,36 +921,38 @@
         }
 
         public int previousIndex() {
-            return nextIndex-1;
+            return nextIndex - 1;
         }
 
         public void remove() {
             checkForComodification();
-            Entry<E> lastNext = lastReturned.next;
-            try {
-                LinkedList.this.remove(lastReturned);
-            } catch (NoSuchElementException e) {
+            if (lastReturned == null)
                 throw new IllegalStateException();
-            }
-            if (next==lastReturned)
+
+            Node<E> lastNext = lastReturned.next;
+            unlink(lastReturned);
+            if (next == lastReturned)
                 next = lastNext;
             else
                 nextIndex--;
-            lastReturned = header;
+            lastReturned = null;
             expectedModCount++;
         }
 
         public void set(E e) {
-            if (lastReturned == header)
+            if (lastReturned == null)
                 throw new IllegalStateException();
             checkForComodification();
-            lastReturned.element = e;
+            lastReturned.item = e;
         }
 
         public void add(E e) {
             checkForComodification();
-            lastReturned = header;
-            addBefore(e, next);
+            lastReturned = null;
+            if (next == null)
+                linkLast(e);
+            else
+                linkBefore(e, next);
             nextIndex++;
             expectedModCount++;
         }
@@ -779,41 +963,18 @@
         }
     }
 
-    private static class Entry<E> {
-        E element;
-        Entry<E> next;
-        Entry<E> previous;
+    private static class Node<E> {
+        E item;
+        Node<E> next;
+        Node<E> prev;
 
-        Entry(E element, Entry<E> next, Entry<E> previous) {
-            this.element = element;
+        Node(Node<E> prev, E element, Node<E> next) {
+            this.item = element;
             this.next = next;
-            this.previous = previous;
+            this.prev = prev;
         }
     }
 
-    private Entry<E> addBefore(E e, Entry<E> entry) {
-        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
-        newEntry.previous.next = newEntry;
-        newEntry.next.previous = newEntry;
-        size++;
-        modCount++;
-        return newEntry;
-    }
-
-    private E remove(Entry<E> e) {
-        if (e == header)
-            throw new NoSuchElementException();
-
-        E result = e.element;
-        e.previous.next = e.next;
-        e.next.previous = e.previous;
-        e.next = e.previous = null;
-        e.element = null;
-        size--;
-        modCount++;
-        return result;
-    }
-
     /**
      * @since 1.6
      */
@@ -821,9 +982,11 @@
         return new DescendingIterator();
     }
 
-    /** Adapter to provide descending iterators via ListItr.previous */
-    private class DescendingIterator implements Iterator {
-        final ListItr itr = new ListItr(size());
+    /**
+     * Adapter to provide descending iterators via ListItr.previous
+     */
+    private class DescendingIterator implements Iterator<E> {
+        private final ListItr itr = new ListItr(size());
         public boolean hasNext() {
             return itr.hasPrevious();
         }
@@ -835,29 +998,32 @@
         }
     }
 
-    /**
-     * Returns a shallow copy of this <tt>LinkedList</tt>. (The elements
-     * themselves are not cloned.)
-     *
-     * @return a shallow copy of this <tt>LinkedList</tt> instance
-     */
-    public Object clone() {
-        LinkedList<E> clone = null;
+    @SuppressWarnings("unchecked")
+    private LinkedList<E> superClone() {
         try {
-            clone = (LinkedList<E>) super.clone();
+            return (LinkedList<E>) super.clone();
         } catch (CloneNotSupportedException e) {
             throw new InternalError();
         }
+    }
+
+    /**
+     * Returns a shallow copy of this {@code LinkedList}. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this {@code LinkedList} instance
+     */
+    public Object clone() {
+        LinkedList<E> clone = superClone();
 
         // Put clone into "virgin" state
-        clone.header = new Entry<E>(null, null, null);
-        clone.header.next = clone.header.previous = clone.header;
+        clone.first = clone.last = null;
         clone.size = 0;
         clone.modCount = 0;
 
         // Initialize clone with our elements
-        for (Entry<E> e = header.next; e != header; e = e.next)
-            clone.add(e.element);
+        for (Node<E> x = first; x != null; x = x.next)
+            clone.add(x.item);
 
         return clone;
     }
@@ -879,8 +1045,8 @@
     public Object[] toArray() {
         Object[] result = new Object[size];
         int i = 0;
-        for (Entry<E> e = header.next; e != header; e = e.next)
-            result[i++] = e.element;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
         return result;
     }
 
@@ -894,7 +1060,7 @@
      *
      * <p>If the list fits in the specified array with room to spare (i.e.,
      * the array has more elements than the list), the element in the array
-     * immediately following the end of the list is set to <tt>null</tt>.
+     * immediately following the end of the list is set to {@code null}.
      * (This is useful in determining the length of the list <i>only</i> if
      * the caller knows that the list does not contain any null elements.)
      *
@@ -903,15 +1069,15 @@
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a list known to contain only strings.
+     * <p>Suppose {@code x} is a list known to contain only strings.
      * The following code can be used to dump the list into a newly
-     * allocated array of <tt>String</tt>:
+     * allocated array of {@code String}:
      *
      * <pre>
      *     String[] y = x.toArray(new String[0]);</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of the list are to
      *          be stored, if it is big enough; otherwise, a new array of the
@@ -922,14 +1088,15 @@
      *         this list
      * @throws NullPointerException if the specified array is null
      */
+    @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
         if (a.length < size)
             a = (T[])java.lang.reflect.Array.newInstance(
                                 a.getClass().getComponentType(), size);
         int i = 0;
         Object[] result = a;
-        for (Entry<E> e = header.next; e != header; e = e.next)
-            result[i++] = e.element;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
 
         if (a.length > size)
             a[size] = null;
@@ -940,8 +1107,8 @@
     private static final long serialVersionUID = 876323262645176354L;
 
     /**
-     * Save the state of this <tt>LinkedList</tt> instance to a stream (that
-     * is, serialize it).
+     * Saves the state of this {@code LinkedList} instance to a stream
+     * (that is, serializes it).
      *
      * @serialData The size of the list (the number of elements it
      *             contains) is emitted (int), followed by all of its
@@ -956,14 +1123,15 @@
         s.writeInt(size);
 
         // Write out all elements in the proper order.
-        for (Entry e = header.next; e != header; e = e.next)
-            s.writeObject(e.element);
+        for (Node<E> x = first; x != null; x = x.next)
+            s.writeObject(x.item);
     }
 
     /**
-     * Reconstitute this <tt>LinkedList</tt> instance from a stream (that is
-     * deserialize it).
+     * Reconstitutes this {@code LinkedList} instance from a stream
+     * (that is, deserializes it).
      */
+    @SuppressWarnings("unchecked")
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         // Read in any hidden serialization magic
@@ -972,12 +1140,8 @@
         // Read in size
         int size = s.readInt();
 
-        // Initialize header
-        header = new Entry<E>(null, null, null);
-        header.next = header.previous = header;
-
         // Read in all elements in the proper order.
-        for (int i=0; i<size; i++)
-            addBefore((E)s.readObject(), header);
+        for (int i = 0; i < size; i++)
+            linkLast((E)s.readObject());
     }
 }
--- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Fri Nov 06 19:48:09 2009 +0300
+++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Fri Nov 06 16:07:52 2009 -0800
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.util.LinkedList;
 import java.util.HashSet;
+import java.util.Iterator;
 
 /**
  * Manipulates a native array of epoll_event structs on Linux:
@@ -200,12 +201,9 @@
     void release(SelChImpl channel) {
         synchronized (updateList) {
             // flush any pending updates
-            int i = 0;
-            while (i < updateList.size()) {
-                if (updateList.get(i).channel == channel) {
-                    updateList.remove(i);
-                } else {
-                    i++;
+            for (Iterator<Updator> it = updateList.iterator(); it.hasNext();) {
+                if (it.next().channel == channel) {
+                    it.remove();
                 }
             }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/Selector/LotsOfCancels.java	Fri Nov 06 16:07:52 2009 -0800
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2009 Google 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.
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Reproduces O(N^2) behavior of JDK6/7 select() call. This happens when
+ * a selector has many unprocessed updates to its interest set (e.g. adding
+ * OP_READ on a bunch of newly accepted sockets). The O(N^2) is triggered
+ * by cancelling a number of selection keys (or just closing a few sockets).
+ * In this case, select() will first go through the list of cancelled keys
+ * and try to deregister them. That deregistration is O(N^2) over the list
+ * of unprocessed updates to the interest set.
+ *
+ * <p> This O(N^2) behavior is a BUG in JVM and should be fixed.
+ *
+ * <p> The test first creates initCount connections, and adds them
+ * to the server epoll set. It then creates massCount connections,
+ * registers interest (causing updateList to be populated with massCount*2
+ * elements), but does not add them to epoll set (that would've cleared
+ * updateList). The test then closes initCount connections, thus populating
+ * deregistration queue. The subsequent call to selectNow() will first process
+ * deregistration queue, performing O(N^2) over updateList size,
+ * equal to massCount * 2.
+ *
+ * <p> Note that connect rate is artificially slowed down to compensate
+ * for what I believe is a Linux bug, where too high of a connection rate
+ * ends up in SYN's being dropped and then slow retransmits.
+ *
+ * @author Igor Chernyshev
+ */
+public class LotsOfCancels {
+
+    static long testStartTime;
+
+    public static void main(String[] args) throws Exception {
+        // the final select should run in less than 1000ms.
+        runTest(500, 2700, 1000);
+    }
+
+    static void log(String msg) {
+        System.out.println(getLogPrefix() + msg);
+    }
+
+    static String getLogPrefix() {
+        return durationMillis(testStartTime) + ": ";
+    }
+
+    /**
+     * Returns the elapsed time since startNanos, in milliseconds.
+     * @param startNanos the start time; this must be a value returned
+     * by {@link System.nanoTime}
+     */
+    static long durationMillis(long startNanos) {
+        return (System.nanoTime() - startNanos) / (1000L * 1000L);
+    }
+
+    static void runTest(int initCount, int massCount, int maxSelectTime)
+            throws Exception {
+        testStartTime = System.nanoTime();
+
+        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7359);
+
+        // Create server channel, add it to selector and run epoll_ctl.
+        log("Setting up server");
+        Selector serverSelector = Selector.open();
+        ServerSocketChannel server = ServerSocketChannel.open();
+        server.configureBlocking(false);
+        server.socket().bind(address, 5000);
+        server.register(serverSelector, SelectionKey.OP_ACCEPT);
+        serverSelector.selectNow();
+
+        log("Setting up client");
+        ClientThread client = new ClientThread(address);
+        client.start();
+        Thread.sleep(100);
+
+        // Set up initial set of client sockets.
+        log("Starting initial client connections");
+        client.connectClients(initCount);
+        Thread.sleep(500);  // Wait for client connections to arrive
+
+        // Accept all initial client sockets, add to selector and run
+        // epoll_ctl.
+        log("Accepting initial connections");
+        List<SocketChannel> serverChannels1 =
+            acceptAndAddAll(serverSelector, server, initCount);
+        if (serverChannels1.size() != initCount) {
+            throw new Exception("Accepted " + serverChannels1.size() +
+                                " instead of " + initCount);
+        }
+        serverSelector.selectNow();
+
+        // Set up mass set of client sockets.
+        log("Requesting mass client connections");
+        client.connectClients(massCount);
+        Thread.sleep(500);  // Wait for client connections to arrive
+
+        // Accept all mass client sockets, add to selector and do NOT
+        // run epoll_ctl.
+        log("Accepting mass connections");
+        List<SocketChannel> serverChannels2 =
+            acceptAndAddAll(serverSelector, server, massCount);
+        if (serverChannels2.size() != massCount) {
+            throw new Exception("Accepted " + serverChannels2.size() +
+                                " instead of " + massCount);
+        }
+
+        // Close initial set of sockets.
+        log("Closing initial connections");
+        closeAll(serverChannels1);
+
+        // Now get the timing of select() call.
+        log("Running the final select call");
+        long startTime = System.nanoTime();
+        serverSelector.selectNow();
+        long duration = durationMillis(startTime);
+        log("Init count = " + initCount +
+            ", mass count = " + massCount +
+            ", duration = " + duration + "ms");
+
+        if (duration > maxSelectTime) {
+            System.out.println
+                ("\n\n\n\n\nFAILURE: The final selectNow() took " +
+                 duration + "ms " +
+                 "- seems like O(N^2) bug is still here\n\n");
+            System.exit(1);
+        }
+    }
+
+    static List<SocketChannel> acceptAndAddAll(Selector selector,
+                                               ServerSocketChannel server,
+                                               int expected)
+            throws Exception {
+        int retryCount = 0;
+        int acceptCount = 0;
+        List<SocketChannel> channels = new ArrayList<SocketChannel>();
+        while (channels.size() < expected) {
+            SocketChannel channel = server.accept();
+            if (channel == null) {
+                log("accept() returned null " +
+                    "after accepting " + acceptCount + " more connections");
+                acceptCount = 0;
+                if (retryCount < 10) {
+                    // See if more new sockets got stacked behind.
+                    retryCount++;
+                    Thread.sleep(500);
+                    continue;
+                }
+                break;
+            }
+            retryCount = 0;
+            acceptCount++;
+            channel.configureBlocking(false);
+            channel.register(selector, SelectionKey.OP_READ);
+            channels.add(channel);
+        }
+        // Cause an additional updateList entry per channel.
+        for (SocketChannel channel : channels) {
+            channel.register(selector, SelectionKey.OP_WRITE);
+        }
+        return channels;
+    }
+
+    static void closeAll(List<SocketChannel> channels)
+            throws Exception {
+        for (SocketChannel channel : channels) {
+            channel.close();
+        }
+    }
+
+    static class ClientThread extends Thread {
+        private final SocketAddress address;
+        private final Selector selector;
+        private int connectionsNeeded;
+        private int totalCreated;
+
+        ClientThread(SocketAddress address) throws Exception {
+            this.address = address;
+            selector = Selector.open();
+            setDaemon(true);
+        }
+
+        void connectClients(int count) throws Exception {
+            synchronized (this) {
+                connectionsNeeded += count;
+            }
+            selector.wakeup();
+        }
+
+        @Override
+        public void run() {
+            try {
+                handleClients();
+            } catch (Throwable e) {
+                e.printStackTrace();
+                System.exit(1);
+            }
+        }
+
+        private void handleClients() throws Exception {
+            int selectCount = 0;
+            while (true) {
+                int createdCount = 0;
+                synchronized (this) {
+                    if (connectionsNeeded > 0) {
+
+                        while (connectionsNeeded > 0 && createdCount < 20) {
+                            connectionsNeeded--;
+                            createdCount++;
+                            totalCreated++;
+
+                            SocketChannel channel = SocketChannel.open();
+                            channel.configureBlocking(false);
+                            channel.connect(address);
+                            if (!channel.finishConnect()) {
+                                channel.register(selector,
+                                                 SelectionKey.OP_CONNECT);
+                            }
+                        }
+
+                        log("Started total of " +
+                            totalCreated + " client connections");
+                        Thread.sleep(200);
+                    }
+                }
+
+                if (createdCount > 0) {
+                    selector.selectNow();
+                } else {
+                    selectCount++;
+                    long startTime = System.nanoTime();
+                    selector.select();
+                    long duration = durationMillis(startTime);
+                    log("Exited clientSelector.select(), loop #"
+                        + selectCount + ", duration = " + duration + "ms");
+                }
+
+                int keyCount = -1;
+                Iterator<SelectionKey> keys =
+                    selector.selectedKeys().iterator();
+                while (keys.hasNext()) {
+                    SelectionKey key = keys.next();
+                    synchronized (key) {
+                        keyCount++;
+                        keys.remove();
+                        if (!key.isValid()) {
+                            log("Ignoring client key #" + keyCount);
+                            continue;
+                        }
+                        int readyOps = key.readyOps();
+                        if (readyOps == SelectionKey.OP_CONNECT) {
+                            key.interestOps(0);
+                            ((SocketChannel) key.channel()).finishConnect();
+                        } else {
+                            log("readyOps() on client key #" + keyCount +
+                                " returned " + readyOps);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
--- a/test/java/util/Collection/MOAT.java	Fri Nov 06 19:48:09 2009 +0300
+++ b/test/java/util/Collection/MOAT.java	Fri Nov 06 16:07:52 2009 -0800
@@ -421,8 +421,11 @@
 
     private static void testQueue(Queue<Integer> q) {
         q.clear();
-        for (int i = 0; i < 5; i++)
+        for (int i = 0; i < 5; i++) {
+            testQueueAddRemove(q, null);
+            testQueueAddRemove(q, 537);
             q.add(i);
+        }
         equal(q.size(), 5);
         checkFunctionalInvariants(q);
         q.poll();
@@ -435,6 +438,216 @@
         }
     }
 
+    private static void testQueueAddRemove(final Queue<Integer> q,
+                                           final Integer e) {
+        final List<Integer> originalContents = new ArrayList<Integer>(q);
+        final boolean isEmpty = q.isEmpty();
+        final boolean isList = (q instanceof List);
+        final List asList = isList ? (List) q : null;
+        check(!q.contains(e));
+        try {
+            q.add(e);
+        } catch (NullPointerException npe) {
+            check(e == null);
+            return;                     // Null elements not supported
+        }
+        check(q.contains(e));
+        check(q.remove(e));
+        check(!q.contains(e));
+        equal(new ArrayList<Integer>(q), originalContents);
+
+        if (q instanceof Deque<?>) {
+            final Deque<Integer> deq = (Deque<Integer>) q;
+            final List<Integer> singleton = Collections.singletonList(e);
+
+            // insert, query, remove element at head
+            if (isEmpty) {
+                THROWS(NoSuchElementException.class,
+                       new Fun(){void f(){ deq.getFirst(); }},
+                       new Fun(){void f(){ deq.element(); }},
+                       new Fun(){void f(){ deq.iterator().next(); }});
+                check(deq.peekFirst() == null);
+                check(deq.peek() == null);
+            } else {
+                check(deq.getFirst() != e);
+                check(deq.element() != e);
+                check(deq.iterator().next() != e);
+                check(deq.peekFirst() != e);
+                check(deq.peek() != e);
+            }
+            check(!deq.contains(e));
+            check(!deq.removeFirstOccurrence(e));
+            check(!deq.removeLastOccurrence(e));
+            if (isList) {
+                check(asList.indexOf(e) == -1);
+                check(asList.lastIndexOf(e) == -1);
+            }
+            switch (rnd.nextInt(isList ? 4 : 3)) {
+            case 0: deq.addFirst(e); break;
+            case 1: check(deq.offerFirst(e)); break;
+            case 2: deq.push(e); break;
+            case 3: asList.add(0, e); break;
+            default: throw new AssertionError();
+            }
+            check(deq.peekFirst() == e);
+            check(deq.getFirst() == e);
+            check(deq.element() == e);
+            check(deq.peek() == e);
+            check(deq.iterator().next() == e);
+            check(deq.contains(e));
+            if (isList) {
+                check(asList.get(0) == e);
+                check(asList.indexOf(e) == 0);
+                check(asList.lastIndexOf(e) == 0);
+                check(asList.subList(0, 1).equals(singleton));
+            }
+            switch (rnd.nextInt(isList ? 11 : 9)) {
+            case 0: check(deq.pollFirst() == e); break;
+            case 1: check(deq.removeFirst() == e); break;
+            case 2: check(deq.remove() == e); break;
+            case 3: check(deq.pop() == e); break;
+            case 4: check(deq.removeFirstOccurrence(e)); break;
+            case 5: check(deq.removeLastOccurrence(e)); break;
+            case 6: check(deq.remove(e)); break;
+            case 7: check(deq.removeAll(singleton)); break;
+            case 8: Iterator it = deq.iterator(); it.next(); it.remove(); break;
+            case 9: asList.remove(0); break;
+            case 10: asList.subList(0, 1).clear(); break;
+            default: throw new AssertionError();
+            }
+            if (isEmpty) {
+                THROWS(NoSuchElementException.class,
+                       new Fun(){void f(){ deq.getFirst(); }},
+                       new Fun(){void f(){ deq.element(); }},
+                       new Fun(){void f(){ deq.iterator().next(); }});
+                check(deq.peekFirst() == null);
+                check(deq.peek() == null);
+            } else {
+                check(deq.getFirst() != e);
+                check(deq.element() != e);
+                check(deq.iterator().next() != e);
+                check(deq.peekFirst() != e);
+                check(deq.peek() != e);
+            }
+            check(!deq.contains(e));
+            check(!deq.removeFirstOccurrence(e));
+            check(!deq.removeLastOccurrence(e));
+            if (isList) {
+                check(isEmpty || asList.get(0) != e);
+                check(asList.indexOf(e) == -1);
+                check(asList.lastIndexOf(e) == -1);
+            }
+            equal(new ArrayList<Integer>(deq), originalContents);
+
+            // insert, query, remove element at tail
+            if (isEmpty) {
+                check(deq.peekLast() == null);
+                THROWS(NoSuchElementException.class,
+                       new Fun(){void f(){ deq.getLast(); }});
+            } else {
+                check(deq.peekLast() != e);
+                check(deq.getLast() != e);
+            }
+            switch (rnd.nextInt(isList ? 6 : 4)) {
+            case 0: deq.addLast(e); break;
+            case 1: check(deq.offerLast(e)); break;
+            case 2: check(deq.add(e)); break;
+            case 3: deq.addAll(singleton); break;
+            case 4: asList.addAll(deq.size(), singleton); break;
+            case 5: asList.add(deq.size(), e); break;
+            default: throw new AssertionError();
+            }
+            check(deq.peekLast() == e);
+            check(deq.getLast() == e);
+            check(deq.contains(e));
+            if (isList) {
+                ListIterator it = asList.listIterator(asList.size());
+                check(it.previous() == e);
+                check(asList.get(asList.size() - 1) == e);
+                check(asList.indexOf(e) == asList.size() - 1);
+                check(asList.lastIndexOf(e) == asList.size() - 1);
+                int size = asList.size();
+                check(asList.subList(size - 1, size).equals(singleton));
+            }
+            switch (rnd.nextInt(isList ? 8 : 6)) {
+            case 0: check(deq.pollLast() == e); break;
+            case 1: check(deq.removeLast() == e); break;
+            case 2: check(deq.removeFirstOccurrence(e)); break;
+            case 3: check(deq.removeLastOccurrence(e)); break;
+            case 4: check(deq.remove(e)); break;
+            case 5: check(deq.removeAll(singleton)); break;
+            case 6: asList.remove(asList.size() - 1); break;
+            case 7:
+                ListIterator it = asList.listIterator(asList.size());
+                it.previous();
+                it.remove();
+                break;
+            default: throw new AssertionError();
+            }
+            if (isEmpty) {
+                check(deq.peekLast() == null);
+                THROWS(NoSuchElementException.class,
+                       new Fun(){void f(){ deq.getLast(); }});
+            } else {
+                check(deq.peekLast() != e);
+                check(deq.getLast() != e);
+            }
+            check(!deq.contains(e));
+            equal(new ArrayList<Integer>(deq), originalContents);
+
+            // Test operations on empty deque
+            switch (rnd.nextInt(isList ? 4 : 2)) {
+            case 0: deq.clear(); break;
+            case 1:
+                Iterator it = deq.iterator();
+                while (it.hasNext()) {
+                    it.next();
+                    it.remove();
+                }
+                break;
+            case 2: asList.subList(0, asList.size()).clear(); break;
+            case 3:
+                ListIterator lit = asList.listIterator(asList.size());
+                while (lit.hasPrevious()) {
+                    lit.previous();
+                    lit.remove();
+                }
+                break;
+            default: throw new AssertionError();
+            }
+            testEmptyCollection(deq);
+            check(!deq.iterator().hasNext());
+            if (isList) {
+                check(!asList.listIterator().hasPrevious());
+                THROWS(NoSuchElementException.class,
+                       new Fun(){void f(){ asList.listIterator().previous(); }});
+            }
+            THROWS(NoSuchElementException.class,
+                   new Fun(){void f(){ deq.iterator().next(); }},
+                   new Fun(){void f(){ deq.element(); }},
+                   new Fun(){void f(){ deq.getFirst(); }},
+                   new Fun(){void f(){ deq.getLast(); }},
+                   new Fun(){void f(){ deq.pop(); }},
+                   new Fun(){void f(){ deq.remove(); }},
+                   new Fun(){void f(){ deq.removeFirst(); }},
+                   new Fun(){void f(){ deq.removeLast(); }});
+
+            check(deq.poll() == null);
+            check(deq.pollFirst() == null);
+            check(deq.pollLast() == null);
+            check(deq.peek() == null);
+            check(deq.peekFirst() == null);
+            check(deq.peekLast() == null);
+            check(!deq.removeFirstOccurrence(e));
+            check(!deq.removeLastOccurrence(e));
+
+            check(deq.addAll(originalContents) == !isEmpty);
+            equal(new ArrayList<Integer>(deq), originalContents);
+            check(!deq.addAll(Collections.<Integer>emptyList()));
+            equal(new ArrayList<Integer>(deq), originalContents);
+        }
+    }
+
     private static void testQueueIteratorRemove(Queue<Integer> q) {
         System.err.printf("testQueueIteratorRemove %s%n",
                           q.getClass().getSimpleName());